我最近遇到了这样的情况:
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;
什么好主意吗?
我最近遇到了这样的情况:
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;
什么好主意吗?
当前回答
如果你可以更改类C和D的源代码,那么你可以分别取出类D,并在类C中输入它的同义词:
class CD {
};
class C {
public:
using D = CD;
};
class CD;
其他回答
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) { }
};
如果存在复杂的构造函数或其他不能顺利继承的特殊成员函数,这种技术可能会带来更多麻烦。我可以想象某些模板魔法的反应很糟糕。
但在我这个非常简单的例子中,它似乎是有效的。
如果你可以更改类C和D的源代码,那么你可以分别取出类D,并在类C中输入它的同义词:
class CD {
};
class C {
public:
using D = CD;
};
class CD;
我不认为这是一个答案,但这是一个有趣的发现: 如果在名为C的名称空间中重复声明结构,那么一切都没问题(至少在gcc中是这样)。 当找到C的类定义时,它似乎会无声地覆盖名称空间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;
}
你做不到,这是c++语言的漏洞。您必须取消嵌套的类中的至少一个。
如果你真的想避免在头文件中包含讨厌的头文件,你可以这样做:
进行文件:
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>()
{
// ...
}
但之后:
您必须在调用时指定嵌入类型(特别是如果您的函数不接受任何嵌入类型的参数) 函数不能是虚函数(因为它是模板)
所以,是的,权衡……