头文件保护符
通常,现在写代码时都会随手在头文件中加入头文件保护符。有以下两种形式的保护符。
#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