我有A和B类,两个都有包含防护的头文件。一个人读到:
#ifndef A_H
#define A_H
#include "B.h"
class A
{
B b;
};
#endif
另一个:
#ifndef B_H
#define B_H
#include "A.h"
class B
{
A a;
};
#endif
现在我使用以下main.cpp测试它:
#include "A.h"
int main()
{
A a;
}
编译错误如下:
# make main
g++ main.cpp -o main
B.h:8: error: ‘A’ does not name a type
除了使用指针/引用和前向声明之外,是否有解决此问题的方法?
答案 0 :(得分:4)
不,这是不可能的:其中一个需要是指针或引用:因为如果A包含B,其中包含A,其中包含B,那么您将获得无限递归并尝试指定无限大小的对象。 / p>
答案 1 :(得分:2)
遗憾的是,没有别的选择,除了使用指针/引用和转发声明。
答案 2 :(得分:1)
你不能这样做,你会导致无限递归(A会包含B,B会包括,A ...),加上编译器不允许它,因为在其中一个类声明中另一个类将是不完整的。 (未完全定义)
如果其中一个是指针或参考,你可以这样做。
答案 3 :(得分:1)
如果可能的话,我建议使用pImpl习语(指向实现,其他名称:不透明指针,Handle-body惯用法,Cheshire Cat ...有关详细信息,请参阅here。)
它基本上允许您从类的用户通常可见的实现细节中“释放”您的类声明(即使它们不可用,假设private
访问)。
您只需按如下方式声明您的课程:
#ifndef A_H
#define A_H
class A{
public:
//declare public methods -> "interface"
private:
struct Private;
Private * mp_d; //feel free to use smart pointer
};
#endif
前向声明struct
(或class
)仅在源文件中定义,并包含所有实现详细信息,例如您的类内部的数据成员和函数。
#include "B.h"
struct A::Private {
B a;
};
A::A() : mp_d( new Private()) {
}
A::~A(){
delete mp_d; //not required if using smart pointer
}
NB:现在,编译器生成的复制构造函数和分配运算符不再起作用(如预期的那样)。确保要么自己实现它们,要么只是通过声明它们private
来阻止编译器生成它们(没有实现)。 (这基本上是C ++ 03风格;我认为在C ++ 11中你只需在声明后添加= delete
以防止编译生成。)
编辑:添加了pImpl的“长”名称