我最近遇到了这样的情况:
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;
有什么想法吗?
答案 0 :(得分:208)
你做不到,这是C ++语言的一个漏洞。您必须取消嵌套至少一个嵌套类。
答案 1 :(得分:31)
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) { }
};
如果有复杂的构造函数或其他特殊成员函数没有顺利继承,那么这种技术可能比它的价值更大。我可以想象某些模板魔法反应很糟糕。
但在我非常简单的情况下,似乎有效。
答案 2 :(得分:3)
如果你真的想避免#include头文件中令人讨厌的头文件,你可以这样做:
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>()
{
// ...
}
但是:
所以,是的,权衡......
答案 3 :(得分:2)
这可以通过将外层声明为命名空间来完成。
示例:我们必须使用嵌套类others :: A :: Nested in others_a.h,这是我们无法控制的。
others_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
#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
#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();
}
答案 4 :(得分: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;
}
答案 5 :(得分: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
}
答案 6 :(得分:0)
如果您有权更改C类和D类的源代码,则可以单独取出D类,并在C类中为其输入同义词:
class CD {
};
class C {
public:
using D = CD;
};
class CD;