C++ C+中嵌套类型/类的前向声明+;

C++ C+中嵌套类型/类的前向声明+;,c++,class,nested,forward-declaration,C++,Class,Nested,Forward Declaration,我最近陷入了这样的境地: class A { public: typedef struct/class {…} B; … C::D *someField; } class C { public: typedef struct/class {…} D; … A::B *someField; } 通常可以声明类名: class A; 但是不能向前声明嵌套类型,以下原因会导致编译错误 class C::D; 有什么想法吗?< P > >你不能这么做,这是C++语

我最近陷入了这样的境地:

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

class C
{
public:
    typedef struct/class {…} D;
…
    A::B *someField;
}
通常可以声明类名:

class A;
但是不能向前声明嵌套类型,以下原因会导致编译错误

class C::D;

有什么想法吗?< P > >你不能这么做,这是C++语言中的一个漏洞。您必须取消嵌套至少一个嵌套类。

我不认为这是一个答案,但这是一个有趣的发现: 如果在名为C的命名空间中重复结构声明,则一切正常(至少在gcc中)。 当找到C的类定义时,它似乎会悄悄地覆盖NAMC空间

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;
}
我需要一个前瞻性的参考,比如:

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) { }
};
#包括
//我这样定义向前参考:
类IDontControl\u嵌套:公共IDontControl::嵌套
{
//需要在此创建转发构造函数
IDontControl_嵌套(inti):嵌套(i){
};
如果存在复杂的构造函数或其他无法顺利继承的特殊成员函数,则此技术可能会遇到更多麻烦。我可以想象某些模板魔法的反应会很糟糕


但在我非常简单的例子中,它似乎是有效的。

如果你真的想避免在头文件中包含讨厌的头文件,你可以这样做:

hpp文件:

class-MyClass
{
公众:
模板
void doesStuff();
};
cpp文件

#包括“MyClass.hpp”
#包括“第三方.hpp”
模板void MyClass::doesStuff()
{
// ...
}
但是:

  • 您必须在调用时指定嵌入类型(特别是如果您的函数不接受任何嵌入类型的参数)
  • 您的函数不能是虚拟的(因为它是一个模板)

  • 因此,是的,权衡…

    这将是一个解决办法(至少对于问题中描述的问题——而不是实际问题,即当无法控制
    C
    的定义时):


    这可以通过将外部类声明为命名空间来实现

    示例:我们必须使用嵌套类others::a::嵌套在others_a.h中,这是我们无法控制的

    其他

    namespace others {
    struct A {
        struct Nested {
            Nested(int i) :i(i) {}
            int i{};
            void print() const { std::cout << i << std::endl; }
        };
    };
    }
    
    名称空间其他{
    结构A{
    嵌套结构{
    嵌套(inti):i(i){}
    int i{};
    
    void print()const{std::cout如果您有权更改类C和D的源代码,则可以分别取出类D,并在类C中输入它的同义词:

    class CD {
    
    };
    
    class C {
    public:
    
        using D = CD;
    
    };
    
    class CD;
    

    为什么需要它?请注意,如果它是被定义的同一个类的成员,则可以向前声明:类X{class Y;Y*a;};类X::Y{};这个解决方案对我有效(命名空间C{class D;};):我找到了一个解决方案,我在cygwin gcc中尝试了这个方法,但如果您尝试在类a定义中引用a.someField.C::D,它就不会编译。它实际上引用了命名空间中的(空)结构,而不是类C中的结构(顺便说一句,它不会在MSVC中编译)。它给出了错误:“'class C'重新声明为不同类型的符号”看起来像是一个GCC错误。它似乎认为名称空间名称可以在同一范围内隐藏类名。谢谢你的回答。在我的情况下,它们不是我的嵌套类。我希望通过一点向前引用来避免一个巨大的库头文件依赖。我想知道C++11是否修复了它?哦。这正是我不想让google出现的。无论如何,谢谢你的帮助他回答得很简洁。同样的,这里有人知道为什么不可能吗?似乎有有效的用例,这种缺乏可以在某些情况下阻止体系结构的一致性。你可以使用朋友,并且只需评论一下,你就可以用它来处理C++中的漏洞。在C++11中,你可以通过
    在派生类中使用basename::basename;
    来继承构造函数,这样复杂的构造函数就没有问题了。这是一个很好的技巧,但如果在同一个头中使用指向IDontControl::Nested的指针(它在头中向前声明),它将不起作用并从外部代码访问,该代码还包括IDontControl的完整定义。(因为编译器将不匹配IDontControl_Nested和IDontControl::Nested)解决方法是执行静态的CAST。我建议做相反的操作,让类在外面,在类中使用<代码> Type Fux/Cuth>,Heck是一个代码> HPP< /Cord>文件LOL,一个.HPP头文件用于C++项目,以区别于C文件头文件,通常在.SA中使用C++和C。ME项目有些人喜欢C++文件的HPP和.CPP,明确地处理它们处理的文件类型,以及C文件的.H和.C。它可能是有效的,但它是无文件的。它的工作原理是:<代码>:::B/<代码>以相同的方式被破坏,不管<代码> < /COD>是类或命名空间。它不能用CLAN或GCC工作。发现外部类被声明为与命名空间不同的东西。
    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
    }
    
    namespace others {
    struct A {
        struct Nested {
            Nested(int i) :i(i) {}
            int i{};
            void print() const { std::cout << i << std::endl; }
        };
    };
    }
    
    #ifndef MY_CLASS_CPP
    // A is actually a class
    namespace others { namespace A { class Nested; } }
    #endif
    
    class MyClass {
    public:
        MyClass(int i);
        ~MyClass();
        void print() const;
    private:
        std::unique_ptr<others::A::Nested> _aNested;
    };
    
    #include "others_a.h"
    #define MY_CLASS_CPP // Must before include my_class.h
    #include "my_class.h"
    
    MyClass::MyClass(int i) :
        _aNested(std::make_unique<others::A::Nested>(i)) {}
    MyClass::~MyClass() {}
    void MyClass::print() const {
        _aNested->print();
    }
    
    class CD {
    
    };
    
    class C {
    public:
    
        using D = CD;
    
    };
    
    class CD;