C/C++——头文件重复包含问题

来源:互联网 发布:淘宝客服介入处理时间 编辑:程序博客网 时间:2024/05/01 06:36

C++程序设计中,一般将类的声明,类的定义分开,将类的声明放在.h的头文件中,而将类的定义放在.cpp的源文件中,这样我们的程序设计起来更加的模块化也清晰明了。但是,这样的设计也会带来一些问题,一个典型的问题就是重复定义问题。如果从一个类派生出一个类,派生类声明时需要包含基类的头文件,如果再在主函数包含这个头文件,编译时就报错,编译器出现重复定义的问题,给出重定义错误提示。

我们先看看下面这个程序。首先我们在新建工程下新建两个.h的头文件(文件名分别为people.h和 student.h),继续新建三个.cpp的源文件(文件名分别是people.cpp、student.cpp、main.cpp),然后编辑相应的代码。

//people.h头文件

#include<iostream>

using namespace std;

class people            //定义一个类people,类有一个成员函数breath()

{

public:

       voidbreath();

};

 

//student.h头文件        //定义一个类student,从类people继承得到,重写成员函数breath()

#include"people.h"

#include<iostream>

using namespace std;

class student :public people     

{

public:

       voidbreath();

};

 

//people.cpp源文件    //定义类people的breath()方法

#include"people.h"

void people::breath()

{    

cout << "poeple"<< endl;

}

 

//student.cpp源文件   //重写类student的breath()方法

#include"student.h"

void student::breath()

{    

cout << "student"<< endl;

 }

 

//main.cpp源文件

#include"people.h"

#include"student.h"

int main()

{    

       people p;        //实例化类people的一个对象p

       student s;       //实例化类student的一个对象s

       p.breath();      //调用函数

       s.breath();

       return 0;

}

在vs2013中对三个源文件进行分别编译,对于people.cpp和student.cpp编译时,没有错误,而对main.cpp编译时显示错误errorC2011: “people”:“class”类型重定义,说明类重复定义。我们来分析一下原因。在main.cpp源文件中,发现#include"people.h"此句代码,编译器回去查找people.h头文件,发现people这个类的定义,继续执行,执行到#include"student.h"这句代码时,编译器便会去查找student.h头文件,在student.h头文件中,编译器执行到#include" people.h"时,便又去查找people.h头文件中的代码,再次发现类people的定义,这样,由于include嵌套造成类people重复定义了两次,编译器便会报错。

对于这种轻量程序,我们可以通过将所有代码写在一个源文件中,包括类的声明和定义,还有主函数,这样就不用写#include"people.h"#include"student.h"但对于大程序,这种方式显然是行不通的,不但会让代码显得冗长而且没有条理。因此对于这种情况,最常用的方法是用条件编译#ifndef…#define…#endif语句。修改上面people.h和student.h文件。

//people.h头文件

#ifndef A

#define A

#include<iostream>

using namespace std;

class people

{

public:

       voidbreath();

};

 

#endif

 

//student.h头文件   

#ifndef B

#define B

 

#include"people.h"

#include<iostream>

using namespace std;

class student :public people

{

public:

       voidbreath();

};

#endif

经过上面的修改,这个程序就可以通过编译了。观察改写后的代码,发现我们在类的定义前后分别加上了#ifndef…#define…#endif语句,当编译器编译main.cpp源文件中的代码,发现#include"people.h"此句代码,编译器回去查找people.h头文件,走到#ifndef B时,编译器会做出如下的判断,若A没有被定义,便定义它(#define A被执行)继续往下走,走到#include"student.h"这句代码时,编译器便会去查找student.h头文件,在student.h头文件中,编译器走到#include " people.h"时,便又去查找people.h头文件中的代码,与上面的一样,编译器会判断A定义了没有,若没有,便进行定义,反之,将跳过#ifndef…#endif间的代码,继续往下走,直到程序编译完毕。所以通过条件编译就可以解决重复定义的问题。#ifndef B语句中的B表示一个标示符,也可以用自己想用的不与程序冲突的其他标示符,通常用大写,只要每个头文件的标示符是唯一的。一般我们可以取一些表达明了的标示符,如在这里可以用 PEOPLE_H。

虽然不是所有的头文件中都要用条件编译,但是,在头文件中使用条件编译避免重复包含,只有好处没有坏处。有时候虽然重复包含一个头文件不会报错,但同样的代码多次编译也是浪费系统资源,所以尽可能地要避免这种重复编译情况。

 

 

参考文献:

http://www.360doc.com/content/12/0428/04/7775902_207173830.shtml

http://www.cnblogs.com/wangh0802PositiveANDupward/archive/2012/07/17/2595678.html

 

 

1 0
原创粉丝点击