该程序由main.cpp、h1.cpp、h1.h三个文件组成,公有两个编译单元。
1、h1.h
#ifndef _H1 #define _H1 class Utility { public: static const int MAX; enum { OK = 10 }; }; extern int a; #endif
2、h1.cpp
#include <iostream> #include "h1.h" using namespace std; void f() { a = 100; cout << "h1.cpp: a=" << a << endl;
cout << Utility::MAX << endl; }
3、main.cpp
#include <iostream> #include "h1.h" using namespace std; int a = 10; const int Utility::MAX = 1024; extern void f(); //通过extern而不是include方式 int main(void) { int data = Utility::MAX; int b = Utility::OK; f(); cout << a << endl; return 0; }
h1.h头文件声明了main编译单元和h1编译单元公用的变量int a和class Utilitty。而int a和class Utilitty中MAX的定义只能在某一个源文件中进行,本程序是在main.cpp中定义的。如果在h1.h内进行定义,那么main.cpp会通过#include将其包含在自己的编译单元内,此时编译main.cpp完全正确;h1.cpp也会将其包含在自己的编译单元内,编译h1.cpp也完全正确。但是在将h1和main编译单元进行连接时,会出现重复定义错误,因为在h1和main编译单元中各有一份int a和class Utilitty中MAX的定义。
有些同学要说啦,在h1.h头文件中不是已经使用了防止重复引用的措施了吗?
#ifndef _H1
#define _H1
//...
#endif
当头文件第一次被包含时,它被正常处理,符号_H1被定义为1。如果头文件被再次包含,通过条件编译,它的内容被忽略。符号_H1按照被包含头文件的文件名进行取名,以避免由于其他头文件使用相同的符号而引起的冲突。但是,你必须记住预处理器仍将整个头文件读入,即使这个头文件所有内容将被忽略。由于这种处理将托慢编译速度,所以如果可能,应该避免出现多重包含。
使用#ifndef只是防止了头文件被重复包含,但是无法防止变量被重复定义。由于工程中的每个.c或.cpp文件都是独立的解释的,即使头文件有
#ifndef _H1
#define _H1
....
#enfif
在其他文件中只要包含了h1.h就会独立的解释,然后每个.c或者.cpp文件生成独立的标示符。在编译器链接时,就会将工程中所有的符号整合在一起,由于文件中有重名变量,于是就出现了重复定义的错误。