C++ 'include' 的两个头文件互相包含出错

来源:互联网 发布:mac ps 2018无法破解 编辑:程序博客网 时间:2024/06/11 05:15

头文件保护符

通常,现在写代码时都会随手在头文件中加入头文件保护符。有以下两种形式的保护符。

#ifndef ABCDE#define ABCDE//..... 内容#endif

#pragma once

两种模式的作用是相同的,都是只让头文件在解析过程中只会展开一次。

能工作的循环包含情况

今天遇到的问题是循环包含问题,也就是说如下例子

//********************************* a.h 文件#pragma once#include <iostream>#include "b.h"using namespace std;int a = 1;//********************************* b.h文件#pragma once#include "a.h"int b = 1;


这是虽然有循环包含,但是由于有头文件保护符的作用,则两者之间是不冲突的,假设存在以下cpp文件:

#include "a.h"#include "b.h"int main(){    cout << a << endl;    cout << b << endl;}

根据 cpp 文件中包含的头文件的顺序,则该cpp 文件会被展开为如下情况:

//-----------------------------------#include "a.h"#include <iostream>//----------------------#include "b.h"int b = 1;//----------------------using namespace std;int a = 1;//------------------------------------int main(){    cout << a << endl;    cout << b << endl;}


可以看出,该代码的使用完全没有问题、


出错的循环包含情况

但是如果出现以下这种情况,则循环包含会出错,且报错都是编译解析错误,即分号错误,<号错误等毫无问题的错误。

//**************************************** a.h 文件#pragma once#include "b.h";#include <iostream>using namespace std;class A {};//*************************************** b.h 文件#pragma once#include "a.h"class B {A * aptr;};


 cpp文件如下:

#include "a.h"#include "b.h"int main() {}


此时报错就比较迷离了。会出现错误如下:

错误 C2143语法错误: 缺少“;”(在“*”的前面)Project2d:\文档\visual studio 2015\projects\project2\project2\b.h5

错误 C2238意外的标记位于“;”之前Project2d:\文档\visual studio 2015\projects\project2\project2\b.h5


分析时尝试将两个头文件展开在cpp文件中,展开结果如下

//------------------------#include "a.h"//-----------#include "b.h"class B{    A * aptr;};//------------#include <iostream>using namespace std;class A{};//---------------------------int main(){}

此时可以明显看出,问题出现在,当将头文件按其各自在cpp中声明的顺序展开时,会出现在 class B 中,类型 A 未经过声明就使用了的情况。

这个问题难在三个点上:

1. 编译器报错的地方很奇怪,说是分号错误类似的问题,根本无从定位

2. 这个问题在包含顺序变动后很可能就消失了,但是弊端还是存在的。假设上例中 cpp 文件先包含 b.h 再包含 a.h ,则就没有问题

3. 若是不止两个头文件间发生了循环包含,而是多个头文件循环包含,则问题更难定位。如 a 包含 b,b 包含 c,c 包含 a,则比较隐晦。

反思

说明:通常在面向对象编程中,我们在头文件中都是定义类,若两个头文件包含,则说明两个头文件中包含的两个类之间关系高度耦合。即A 需要 B , B 需要 A。依照《重构》中的思想,这种情况属于代码臭味,需要考虑将这两个类中的内容合并为一个类,之后将不存在循环包含的情况。类之间通常是单向依赖关系,双向依赖关系意味着臭味,需要对代码进行拆分重组,因此当出现循环包含时,应当考虑代码重构。 


转载请标明出处:http://blog.csdn.net/virtual_func

0 0
原创粉丝点击