首先我们先建立一个项目,项目文件有:
A.h
B.h
C.h
A.cpp
B.cpp
C.cpp
文件内容如下:
A.h
#ifndef EVENTHANDLER_CEVENTHANDLER_H_HEADER_INCLUDED_BA392BB6
#define EVENTHANDLER_CEVENTHANDLER_H_HEADER_INCLUDED_BA392BB6
#include "B.h"
class A
{
public:
};
#endif
B.h
#ifndef EVENTHANDLER_CEVENTHANDLER_H_HEADER_INCLUDED_BA392BB6B
#define EVENTHANDLER_CEVENTHANDLER_H_HEADER_INCLUDED_BA392BB6B
#include "C.h"
class B
{
public:
};
#endif
C.h
#ifndef EVENTHANDLER_CEVENTHANDLER_H_HEADER_INCLUDED_BA392BB6C
#define EVENTHANDLER_CEVENTHANDLER_H_HEADER_INCLUDED_BA392BB6C
#include "A.h"
class C
{
public:
};
#endif
A.cpp
#include "A.h"
B.cpp
#include "B.h"
C.cpp
#include "C.h"
我们先做一个试验,分别注释掉A.cpp,B.cpp,C.cpp中的包含文件,每次只留下一个,比如第一次(A情况)注释掉:B.cpp,C.cpp中的包含文件语句,第二次(B情况)注释掉A.cpp,C.cpp中的包含文件语句,第三次(C情况)注释掉:A.cpp,C.cpp中的包含文件语句,便以结果如下表:
测试用例 | 编译结果 |
A | 编译通过 |
B | 编译出错syntax error : missing ';' before identifier 'b' |
C | 编译通过 |
为什么在B情况下会出现b标识符没有找到呢?我们来分别分析一下这几种情况:
A情况中只有 “A.cpp”文件中包含”A.h”,那么编译器开始首先编译”A.cpp”文件,它首先看到#include “A.h”语句,这时它并不是立刻展开”A.h”,而是会到”A.h”里再找是否有包含别的.h文件,如果有编译器则再到那个.h文件里再找是否有包含其他的.h文件,直到最低层,所以情况变成了在A.h中又找到#include “B.h”,然后又在”C.h”里找到#include “A.h”但此时A.h已经包含过一次了,所以跳出。最终在A.cpp文件里的内容可能是这样:
class C
{
public:
};
class B
{
public:
};
class A
{
public:
};
B情况的分析过程与A类似,在B.cpp文件里的内容可能是这样:
class A
{
public:
};
class C
{
public:
};
class B
{
public:
};
C情况的分析过程一样,在C.cpp文件里的内容可能是这样:
class B
{
public:
};
class A
{
public:
};
class C
{
public:
};
经过上面的代码可以看出,显然B情况是错误的,而且确实B在出现以前并没有声明。
其实头文件包含过程很像一个栈的调用过程,编译器会去找文件中包含的那个头文件里是否包含其他的头文件,直到找到最底层头文件或没有包含头文件为止,然后再一层一层返回展开头文件里面的内容。
这篇文章的目的是为了说清楚头文件出现循环包含时,代码可能的呈现,因为只要你知道代码的呈现就很容易解决头文件循环包含的错误,就上上面变量没有找到的错误。文章仓促写成肯定会有错误,望大家多指正交流。