2009-06-04 83 views
164

我最近陷在像這樣的情況的向前聲明聲明一個嵌套類型,下面的原因會導致編譯錯誤。用C嵌套類型/類++

class C::D; 

任何想法?

+5

爲什麼你需要那個?請注意,如果它是被定義的同一類的成員,則可以轉發聲明:class X {class Y; Y * a; }; class X :: Y {}; – 2009-06-04 15:33:15

+1

迷人的錯誤。 – 2009-06-04 15:55:50

+0

此解決方案適用於我(namespace C {class D;};):http://stackoverflow.com/questions/22389784/c-code-fails-to-compile-after-upgrading-xcode-5-0-5 -1向前聲明 – 2016-08-16 16:43:28

回答

179

你不能這樣做,這是C++語言的漏洞。您必須取消嵌套至少一個嵌套類。

+5

感謝您的答覆。在我的情況下,他們不是我的嵌套類。我希望避免一個巨大的庫頭文件依賴與一點前向參考。我不知道C++ 11是否修復了它? – 2011-11-07 00:57:44

0

我不會說這個答案,但仍然是一個有趣的發現: 如果你重複在一個名爲C的名稱空間中聲明你的結構,一切都很好(至少在gcc中)。 當C的類定義被發現,它似乎靜靜地覆蓋namspace C.

namespace C { 
    typedef struct {} D; 
} 

class A 
{ 
public: 
typedef struct/class {...} B; 
... 
C::D *someField; 
} 

class C 
{ 
public: 
    typedef struct/class {...} D; 
... 
    A::B *someField; 
} 
25
class IDontControl 
{ 
    class Nested 
    { 
     Nested(int i); 
    }; 
}; 

我需要像前參考:

class IDontControl::Nested; // But this doesn't work. 

我的解決方法是:

class IDontControl_Nested; // Forward reference to distinct name. 

後來我可以使用全定義:

#include <idontcontrol.h> 

// I defined the forward ref like this: 
class IDontControl_Nested : public IDontControl::Nested 
{ 
    // Needed to make a forwarding constructor here 
    IDontControl_Nested(int i) : Nested(i) { } 
}; 

如果存在複雜的構造函數或其他沒有順利繼承的特殊成員函數,這種技術可能比它的價值更麻煩。我可以想象某些模板魔法反應糟糕。

但在我的非常簡單的情況下,它似乎工作。

3

如果你真的想避免#包括討厭的頭文件在你的頭文件,你可以這樣做:

HPP文件:

class MyClass 
{ 
public: 
    template<typename ThrowAway> 
    void doesStuff(); 
}; 

CPP文件

#include "MyClass.hpp" 
#include "Annoying-3rd-party.hpp" 

template<> void MyClass::doesStuff<This::Is::An::Embedded::Type>() 
{ 
    // ... 
} 

但是:

  1. 您必須指定在調用時嵌入的類型(特別是如果你的函數不採取嵌入類型的任何參數)
  2. 你的函數不能是虛擬的(因爲它是一個模板)

所以,是的,權衡...

0

這將是一個解決方法(至少對於問題中描述的問題 - 不是爲了實際問題,即,當不能控制C的定義時):

class C_base { 
public: 
    class D { }; // definition of C::D 
    // can also just be forward declared, if it needs members of A or A::B 
}; 
class A { 
public: 
    class B { }; 
    C_base::D *someField; // need to call it C_base::D here 
}; 
class C : public C_base { // inherits C_base::D 
public: 
    // Danger: Do not redeclare class D here!! 
    // Depending on your compiler flags, you may not even get a warning 
    // class D { }; 
    A::B *someField; 
}; 

int main() { 
    A a; 
    C::D * test = a.someField; // here it can be called C::D 
}