文件相互包含的错误问题
序言
文件相互包含的错误问题实际是两个类相互包含,从而引起的声明先后问题
可能会有的疑问
1、头文件里明明有Header Guards(防卫式声明):
#ifdef
#define
#endif
怎么还会产生所谓的文件相互包含的问题呢?
溪渣渣:Header Guards(防卫式声明)确实有效防止头文件重复包含,但也引出了本章实际错误:两个类相互包含
原因分析
C2504: 未定义的基类
其实这个原因是因为编译基类的h文件中,包含了派生类的h文件,导致派生类在基类之前就已经声明,但是虽然提前声明,可基类依然还是没有声明。
光看文字是很苍白无力的,我举个例子
//AA.h
#ifndef AA_H
#define AA_H
#include "BB.h"
class AA
{
...
两种情况:
1、直接用到BB类
2、CC类里用到BB类,间接联系起来,等同于直接用到BB类
...
};
#endif
//BB.h
#ifndef BB_H
#define BB_H
#include "AA.h"
class BB :public AA
{
...
};
#endif
说到这,就不得不说#include “”/<>的本质了,这实质是把对应的h文件内容copy过来放到该头文件里面,所以实际是这样的:
在编译AA.h时,其实际头文件是:
//AA.h
#ifndef AA_H
#define AA_H
//BB.h
#ifndef BB_H
#define BB_H
#ifndef AA_H //已有宏定义,所以再次包含的不编译
...
#endif
class BB :public AA //BB要编译,就需要AA类,但AA类在后面,等同于AA类并没有任何声明,故报错 C2504: 未定义的基类
{
...
};
#endif
class AA
{
...
两种情况:
1、直接用到BB类
2、CC类里用到BB类,间接联系起来,等同于直接用到BB类
...
};
#endif
.
C2143: 语法错误: 缺少“;”(在“*”的前面)
C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
C2238: 意外的标记位于“;”之前
该原因是因为AA包含的BB类,没有在AA之前声明,所以"BB"等同于不存在的符号,因此报错。
在编译BB.h时,其实际头文件是:
//BB.h
#ifndef BB_H
#define BB_H
//AA.h
#ifndef AA_H
#define AA_H
#ifndef BB_H //已有宏定义,所以再次包含的不编译
...
#endif
//AA要想成功声明,首先就需要包含有的BB类的声明了,毕竟BB不存在的话,AA就无法成功声明,所以等同于
class AA //BB只是个乱写的符号,所以编译器无法识别,所以会报上面的错误
{
...
两种情况:
1、直接用到BB类
2、CC类里用到BB类,间接联系起来,等同于直接用到BB类
...
};
#endif
class BB :public AA
{
...
};
#endif
解决方案
以上面为例
//AA.h
#ifndef AA_H
#define AA_H
class BB;
class AA
{
...
两种情况:
1、直接用到BB类
2、CC类里用到BB类,间接联系起来,等同于直接用到BB类
...
};
#endif
//AA.cpp
#include "AA.h"
#include "BB.h"
...
#endif
BB.h不用改,因为AA.h已经可以成功声明了,BB.h可以正常声明了。
为什么在前面放个class,然后在cpp里面放#include ""就行了呢?
简单来说,就是头文件的只需要个声明,用到类的结构如cpp里才需要#include “”,这就好像下文提前声明一样的道理。
int func();
void fun()
{
cout << func();
}
int func()
{
return 5;
}
在其代入其实是每个cpp文件编译的情况时,你就明白了
值得注意的是,在AA.h里直接BB b或者调用b->func()等操作是不对的,这样头文件里就不是个声明了,是用到类的结构,就算前置了声明也无效,因为实际的定义在后面还没有实际定义好,只需要改为指针BB *暂时替代,在AA.cpp再行#include "BB.h"进行相关对BB的操作即可。