长路漫漫

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

先看一个例子,假设有三个文件:headerA.h、headerB.h、main.cpp,其内容分别如下:

// file: headerA.h
struct foo
{
    int member;
};

// file: headerB.h
#include "headerA.h"

// file: main.cpp
#include "headerA.h"
#include "headerB.h"
int main()
{
    return 0;
}

其中main.cpp中直接包含了headerA.h头文件,而headerB.h中又再次包含了headerA.h,这使得预处理器在处理main.cpp时添加了两份struct foo的定义,违反了One Definition Rule规则,g++会报出“error: redefinition of 'struct foo'”这样的错误。

【说明】:C++03标准定义了One Definition Rule(ODR)规则,它要求:在任何一个编译单元(translation unit)中,模板、类型、函数和对象可以有多次声明,但只能定义一次。

解决方法是使用#include guards(也称为macro guards),即在头文件中定义一个唯一标识该头文件的宏,然后通过判断该宏是否被定义来决定是否编译其中内容,于是上述例子修改如下:

// file: headerA.h
#ifndef __HEADER_A_H__
#define __HEADER_A_H__
struct foo
{
    int member;
};
#endif

// file: headerB.h
#include "headerA.h"

// file: main.cpp
#include "headerA.h"
#include "headerB.h"
int main()
{
    return 0;
}

在每一个头文件中添加预处理指令来避免头文件内容重复被包含,这也是我们最常见的处理方式。但是有一个问题:其中标识头文件的宏必须唯一。当程序使用第三方库时,这一点很难完全保证,因此,目前的很多编译器(包括gcc、clang、vc、intel c++ complier等)提供了预处理指令#pragma once来解决这个问题,于是上述代码还可修改为:

// file: headerA.h
#pragma once
struct foo
{
    int member;
};

// file: headerB.h
#include "headerA.h"

// file: main.cpp
#include "headerA.h"
#include "headerB.h"
int main()
{
    return 0;
}

【说明】:#pragma once并不是C++标准规定的,但是很多编译器都支持它。In the C and C++ programming languages, #pragma once is a non-standard but widely supported preprocessor directive designed to cause the current source file to be included only once in a single compilation. Thus, #pragma once serves the same purpose as #include guards, but with several advantages, including: less code, avoiding name clashes, and sometimes improved compile speed.

posted on 2012-08-22 14:39  opangle  阅读(2997)  评论(1编辑  收藏  举报