文章

头文件相互引用

1.引言

这几天在做一个项目,遇到了想保存单例B里面的数据,于是用了一个单例A

A类里面定义B的对象,想保存单例B某时的状态,所以头文件里有B.h

B类里面的某个成员函数实现需要先实例化A,然后把单例B的状态存在A中的B对象里,所以我在B的头文件里写了A.h

这时候编译器就报错了,提示我们不能在A.h中定义B b

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//A.h

#include"B.h"
class A
{
  //...
  B b
};

//B.h

#include"A.h"
class B
{
    
};

2.解决思路一

首先这是个循环引用,我想的是编译器先编译的A类,此时B类还没有被编译,所以编译器找不到B的声明,于是就报错了

所以用前向声明来解决这个问题,前向声明允许你在一个类知道另一个类的存在,而不需要知道它的所有细节,也就是在A类前,声明B类,但这种有个问题就是,那类就不能写成对象了B b,而应该用指针或者引用的形式

使用前向声明时,你只能声明指向那个类的指针或引用,因为编译器此时并不知道那个类的大小。如果你需要使用那个类的对象或者调用它的方法,那么你就需要包含那个类的头文件。但是,在头文件中尽量避免包含其他头文件,可以减少编译时间,并且避免可能出现的循环引用问题。如果需要使用其他类的对象或方法,尽量在源文件(.cpp文件)中包含相应的头文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//A.h

#include"B.h"
class B;

class A
{
  //...
  B* b
};

//B.h

#include"A.h"
class A;

class B
{
    
};

但是这又不符合我的想法,因为这样的话就用到了指针,而我只不过想让b为一个对象,可以存放B单例的各种数据

百思不得其解的时候,同事给出了这个代码,#include”A.h”不写在B的头文件中,而写在了B的cpp中,这样我发现确实可以,此时B可以定义对象b,也就是解决思路二的代码

3.解决思路二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//A.h

#include"B.h"
class B;

class A
{
  //...
  B b
};

//B.cpp

#include"A.h"

因为头文件的包含(#include)是在预处理阶段完成的,预处理器会把所有的”#include”替换为那个头文件的全部内容。当预处理器在”A.h”中遇到”#include “B.h”“时,它会把”B.h”的内容复制到这里。然后,当预处理器在”B.cpp”中遇到”#include “A.h”“时,它会把”A.h”(此时已经包含了”B.h”的内容)的内容复制到这里。所以,即使”B.cpp”中包含了”A.h”,但是因为这发生在预处理阶段,所以不会产生循环引用的问题。

4.如何保存单例里面的数据呢

本来想用各种拷贝构造,移动构造,发现离开了指针就都G了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/A.h

#include"B.h"
class B;

class A
{
  //...
  B b
};

//B.cpp

#include"A.h"

填坑再写,现在都快0点了

本文由作者按照 CC BY 4.0 进行授权