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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/951234/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:06:44  来源:igfitidea点击:

Forward declaration of nested types/classes in C++

c++classnestedforward-declaration

提问by Calmarius

I recently got stuck in a situation like this:

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

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

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

Usually you can declare a class name:

通常你可以声明一个类名:

class A;

But you can't forward declare a nested type, the following causes compilation error.

但是您不能转发声明嵌套类型,以下会导致编译错误。

class C::D;

Any ideas?

有任何想法吗?

回答by Adam Rosenfield

You can't do it, it's a hole in the C++ language. You'll have to un-nest at least one of the nested classes.

你做不到,这是C++语言的一个漏洞。您必须取消嵌套至少一个嵌套类。

回答by Marsh Ray

class IDontControl
{
    class Nested
    {
        Nested(int i);
    };
};

I needed a forward reference like:

我需要一个前向参考,如:

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

My workaround was:

我的解决方法是:

class IDontControl_Nested; // Forward reference to distinct name.

Later when I could use the full definition:

稍后当我可以使用完整定义时:

#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) { }
};

This technique would probably be more trouble than it's worth if there were complicated constructors or other special member functions that weren't inherited smoothly. I could imagine certain template magic reacting badly.

如果有复杂的构造函数或其他不能顺利继承的特殊成员函数,这种技术可能会比它的价值更麻烦。我可以想象某些模板魔法的反应很糟糕。

But in my very simple case, it seems to work.

但在我非常简单的情况下,它似乎有效。

回答by edenbridge

If you really want to avoid #including the nasty header file in your header file, you could do this:

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

hpp file:

hpp文件:

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

cpp file

.cpp文件

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

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

But then:

但是之后:

  1. you will have to specify the embedded type at call time (especially if your function does not take any parameters of the embedded type)
  2. your function can not be virtual (because it is a template)
  1. 您必须在调用时指定嵌入类型(特别是如果您的函数不采用嵌入类型的任何参数)
  2. 你的函数不能是虚拟的(因为它是一个模板)

So, yeah, tradeoffs...

所以,是的,权衡...

回答by bitlixi

This can be done by forward declare the outer class as a namespace.

这可以通过将外部类向前声明为命名空间来完成

Sample: We have to use a nested class others::A::Nested in others_a.h, which is out of our control.

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

others_a.h

其他_a.h

namespace others {
struct A {
    struct Nested {
        Nested(int i) :i(i) {}
        int i{};
        void print() const { std::cout << i << std::endl; }
    };
};
}

my_class.h

my_class.h

#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;
};

my_class.cpp

my_class.cpp

#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();
}

回答by nschmidt

I would not call this an answer, but nonetheless an interesting find: If you repeat the declaration of your struct in a namespace called C, everything is fine (in gcc at least). When the class definition of C is found, it seems to silently overwrite the namspace C.

我不会称其为答案,但仍然是一个有趣的发现:如果您在名为 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;
}

回答by chtz

This would be a workaround (at least for the problem described in the question -- not for the actual problem, i.e., when not having control over the definition of C):

这将是一种解决方法(至少对于问题中描述的问题 - 不适用于实际问题,即当无法控制 的定义时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
}

回答by Suvorov Ivan

If you have access to change the source code of classes C and D, then you can take out class D separately, and enter a synonym for it in class C:

如果你有权更改C类和D类的源代码,那么你可以单独取出D类,在C类中输入一个同义词:

class CD {

};

class C {
public:

    using D = CD;

};

class CD;