C++<第三十八篇>:如何防止头文件被重复引入

在 C++ 项目中,经常会发生头文件重复引入导致冲突问题。事实上,一个完整的 C++ 项目由多个代码文件组成,根据后缀的不同,大致可以分成两个部分:
(1).h 文件:又称“头文件”,用于存放常量、函数的声明部分、类的声明部分;
(2).cpp 文件:又称“源文件”,用于存放变量、函数的定义部分,类的实现部分;
但是,常常会重复导入.h文件,导致重定义的错误,本文主要是为了解决.h文件重复导入的问题。

C++ 多文件编程中,多次 #include 导致重复引入的演示代码如下:

A.h

class A
{
public:
    A() {}
    void say();
};

A.cpp

#include "A.h"
#include <iostream>

using namespace std;

void A::say()
{
    cout << "AAAAAAAAAAA" << endl;
}

B.h

#include "A.h";

class B
{
private:
    A a;
public:
    void setA(A a);
    A getA();
    void say();
};

B.cpp

#include "B.h"
#include <iostream>

using namespace std;

void B::setA(A a)
{
    this->a = a;
}

A B::getA()
{
    return a;
}

void B::say()
{
    cout << "BBBBBBBBB" << endl;
}

main.cpp

#include <iostream>
#include"A.h"
#include"B.h"

using namespace std;

int main()
{
    A* a = new A();
    B* b = new B();
    b->setA(*a);
    b->getA().say();

    return 0;
}

以上代码运行之后会报如下错误:

image.png

如上错误所示,以上代码 A 类重新定义了,原因是在 main.cpp 文件中引入了 A.h 和 B.h,而在 B.h 中有引入了 A.h,相当于 A.h 被引入了两次,所以会报错。

问题的解决方案有三种,分别是:使用宏定义避免重复引入、使用#pragma once避免重复引入、使用_Pragma操作符。

(1)使用宏定义避免重复引入

在实际多文件开发中,我们往往使用如下的宏定义来避免发生重复引入:

#ifndef _NAME_H
#define _NAME_H
//头文件内容
#endif

其中,_NAME_H 是宏的名称。需要注意的是,这里设置的宏名必须是独一无二的,不要和项目中其他宏的名称相同。

之前演示的代码是 A.h 文件被重复引入,只要修改下 A.h,就可以解决重复引入的问题,修改后的 A.h 代码如下:

#ifndef _A
#define _A
class A
{
public:
    A() {}
    void say();
};
#endif
(2)使用#pragma once避免重复引入

我们还可以使用 #pragma one 指令,将其附加到指定文件的最开头位置,则该文件就只会被 #include 一次。

#ifndef 是通过定义独一无二的宏来避免重复引入的,这意味着每次引入头文件都要进行识别,所以效率不高。但考虑到 C 和 C++ 都支持宏定义,所以项目中使用 #ifndef 规避可能出现的“头文件重复引入”问题,不会影响项目的可移植性。

和 ifndef 相比,#pragma once 不涉及宏定义,当编译器遇到它时就会立刻知道当前文件只引入一次,所以效率很高。但值得一提的是,并不是每个版本的编译器都能识别 #pragma once 指令,一些较老版本的编译器就不支持该指令(执行时会发出警告,但编译会继续进行),即 #pragma once 指令的兼容性不是很好。

目前,几乎所有常见的编译器都支持 #pragma once 指令,甚至于 Visual Studio 2017 新建头文件时就会自带该指令。可以这么说,在 C/C++ 中,#pragma once 是一个非标准但却逐渐被很多编译器支持的指令。

如何使用? 只要在被重复文件的顶部添加 #pragma once 即可。

#pragma once

class A
{
public:
    A() {}
    void say();
};
(3)用_Pragma操作符

C99 标准中新增加了一个和 #pragma 指令类似的 _Pragma 操作符,其可以看做是 #pragma 的增强版,不仅可以实现 #pragma 所有的功能,更重要的是,_Pragma 还能和宏搭配使用。

修改后的代码如下:

_Pragma("once")

class A
{
public:
    A() {}
    void say();
};
总结:

(1) #pragma once 和 _Pragma("once") 可算作一类,其特点是编译效率高,但可移植性差(比如:编译器不支持,会发出警告,但不会中断程序的执行)
(2)而 #ifndef 的特点是可移植性高,编译效率差。

需要知道的是:在某些场景中,考虑到编译效率和可移植性,#pragma once 和 #ifndef 经常被结合使用来避免头文件被重复引入。比如说:

#pragma once
#ifndef _A
#define _A

class A
{
public:
    A() {}
    void say();
};
#endif

[本章完...]

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容