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
Forward declaration of nested types/classes in C++
提问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:
但是之后:
- you will have to specify the embedded type at call time (especially if your function does not take any parameters of the embedded type)
- your function can not be virtual (because it is a template)
- 您必须在调用时指定嵌入类型(特别是如果您的函数不采用嵌入类型的任何参数)
- 你的函数不能是虚拟的(因为它是一个模板)
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;