1

我有 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

除了使用指针/引用和前向声明之外,有没有解决这种情况的方法?

4

4 回答 4

4

不,这是不可能的:其中之一需要是指针或引用:因为如果 A 包含 B,B 包含 A,A 又包含 B,那么您就有无限递归并试图指定无限大小的对象。

于 2012-11-13T17:39:15.617 回答
2

不幸的是,除了使用指针/引用和前向声明之外别无选择。

于 2012-11-13T17:38:19.267 回答
1

你不能这样做,你会导致无限递归(A 将包含 B,B 将包含,A ...),而且编译器不会允许它,因为在一个类声明中,另一个类将是不完整的. (未完全定义)

如果其中之一是指针或引用,则可以这样做。

于 2012-11-13T17:38:29.720 回答
1

如果可能,我建议使用 pImpl 成语(Pointer-to-implementation,其他名称:不透明指针、Handle-body 成语、柴郡猫……详情请参见此处。)

它基本上允许您从您的类用户通常可见的实现细节中“释放”您的类声明(即使它们不可用,假设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
}

注意:现在编译器生成的复制构造函数和赋值运算符不再起作用(如预期的那样)。确保自己实现它们,或者只是通过声明它们private(不实现)来阻止编译器生成它们。(这基本上是 C++03 风格;我认为在 C++11 中,您只需= delete在声明后添加即可防止编译器生成。)

编辑:添加了 pImpl 的“长”名称

于 2012-11-13T17:56:00.137 回答