假设存在a如下文件:
a.cpp a.h b.cpp b.h
上述4个文件分别定义了两个类:类A和类B,假设这两个类需要互相调用,即在a.h中
.....
#include "b.h" //包含B的头文件
class A{
....
}
......
在b.h中同样要包含a.h
.....
#include "a.h" //包含A的头文件
class B{
....
}
......
这样就形成了互相包含。但是这种情况下我们去编译的时候往往会报错
'A' has not been declared
还有
'B' has not been declared
产生这样的原因是什么呢?猛的一看可能觉的互相包含,感觉上形成了递归,越想越复杂,其实不然,在编译阶段存在一个预处理的步骤,预处理的工作就是将头文件中内容复制到包含他的cpp文件中,为了避免产生递归,即每隔头文件在一个cpp文件中仅存在一份拷贝,每个头文件的开头都会看到如下的描述:
#ifndef xxxxx_H
#define xxxxx_H
...
...
...
#endif
这样的描述就形成了一个代码块,含义与条件编译一样,如果该文件中已经存在了该符号,说明在该cpp文件中已经包含了该头文件,不需要再次包含该头文件,直接退出即可,无需再次读取该头文件的内容,这样就形成不了递归了。
那错误是怎样生成的呢?我们仔细分析一下,假设经过上述的预处理步骤后,a.cpp中应该是这样的:
class B{
.....
A* a;
}
class A{
.....
B* b;
}
看看预处理完成后的a.cpp,仔细看看有没有问题,很明显在a.cpp中class A没有问题,但是class B就存在问题了,问题是类B中存在一个成员变量A* a,但是在B之前没有对A的任何声明,所以在编译的时候会提示A没有声明,同样编译b.cpp时也会报类似的错误,大家可以自己推导一下。
总结:
在头文件互相包含时,一定要在每个头文件中要做对互相包含的头文件涉及的类做类的前置声明,
即
#include "b.h"
class B; //前置声明
class A{
...
B* b;
}