大家知道,我们写.h文件时,通常会加上防卫式声明,有以下两种方式:

1. 宏定义

1
2
3
4
#ifndef _FILENAME_
#define _FILENAME_
//...
#endif

2. 编译器指令

1
#pragma once

  

但是,为什么头文件中需要添加这种防卫式声明呢?如果没有这样的声明,会出现怎样的问题。这里,先看一个例子。

-- "Car.h",代码如下(并没有添加防卫式声明):

1
2
3
4
5
// Car.h
class Car
{
// ...
};

-- "Person.h",代码如下(包含了Car.h文件):

1
2
3
4
5
6
7
// Person.h
#include "Car.h"
class Person
{
public:
    Car car;
};

-- 在"main.cpp"中,我们同时include两个头文件:

1
2
3
4
5
6
// main.cpp
#include "Car.h"
#include "Person.h"
int main(int argc, const char * argv[]) <br>{
    Person p;
}

此时,我们会发现编译出错:Redefinition of 'Car'.

可是为什么会出现这样的情况呢?

我们需要知道,在预编译阶段,编译器会把.h文件展开,即main.cpp中的代码可以看做是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Car
{
    // ...
};
 
class Car
{
    // ...
};
 
class Person
{
public:
    Car car;
};
 
int main(int argc, const char * argv[]) {
    Person p;
}

所以,我们可以知道防卫式声明的作用是:防止由于同一个头文件被包含多次,而导致了重复定义。

在这两种声明方式中:

  #ifndef 依赖于宏定义名,当宏已经定义时,#endif之前的代码就会被忽略,但是这里需要注意宏命名重名的问题;

  #pragma once 只能保证同一个文件不会被编译多次,但是当两个不同的文件内容相同时,仍然会出错。而且这是微软提供的编译器命令,当代码需要跨平台时,需要使用宏定义方式。

https://www.cnblogs.com/xyq10612/p/5910933.html

[C++]关于头文件中的防卫式声明的更多相关文章

  1. C++ 多文件编译简述:头文件、链接性、声明与定义

    目录 Commen Sense 头文件 链接性 static 与链接性控制 extern 与外部链接性 Reference Commen Sense C++ 在编译时对每个翻译单元(Translati ...

  2. C++-模板的声明和实现为何要放在头文件中

    源: http://blog.csdn.net/lqk1985/archive/2008/10/24/3136364.aspx 如何组织编写模板程序 发表日期: 1/21/2003 12:28:58 ...

  3. C ++模板的声明和实现为何要放在头文件中?

    源: http://blog.csdn.net/lqk1985/archive/2008/10/24/3136364.aspx 如何组织编写模板程序 发表日期: 1/21/2003 12:28:58 ...

  4. vs2022+resharper创建模板——实现在新建文件的时候自动生成防卫式声明和自定义语句

    在网上找了很久如何让visual studio新建文件的时候自动生成注释和防卫式声明,虽然防卫式声明可以用#proga once替代,但是在clion里可以自动生成vs里面没法自动生成还是觉得难受,于 ...

  5. cctype头文件中的一些内容

    1. string 标准库 1.1初始化 string s1; 默认构造函数s1为空 string s2(s1); 将s2初始化为s1的一个副本 string s3(“value”); 将s3初始化为 ...

  6. Effective Objective-C 2.0 — 第二条:类的头文件中尽量少引入其他头文件

    第二条:类的头文件中尽量少引入其他头文件 使用向前声明(forward declaring) @class EOCEmployer 1, 将引入头文件的实际尽量延后,只在确有需要时才引入,这样就可以减 ...

  7. c语言头文件中定义全局变量的问题

    c语言头文件中定义全局变量的问题 (转http://www.cnblogs.com/Sorean/) 先说一下,全局变量只能定义在 函数里面,任意函数,其他函数在使用的时候用extern声明.千万不要 ...

  8. 将inline、template声明和定义在头文件中

    如果要在要在源文件(a.cpp)中内联的展开一个函数(fun),则该源文件(a.cpp)中必须包含此函数(fun)的定义.如果要在多个文件中内联的展开fun,则在所有的源文件中都必须包含fun的定义. ...

  9. 头文件中的#ifndef/#define/#endif 的作用

    在一个大的软件工程里面,可能会有多个文件同时包含一个头文件,当这些文件编译链接成一个可执行文件时,就会出现大量重定义的错误.在头文件中实用#ifndef #define #endif能避免头文件的重定 ...

随机推荐

  1. javascript面向对象技术基础总结

    javascript面向对象和php不太一样,语法不太相同,总结如下 //cat 对象 function Cat(name,color){ this.name = name;//不确定的成员属性 th ...

  2. 高精度乘法(FFT)

    学会了FFT之后感觉自己征服了世界! 当然是幻觉... 不过FFT还是很有用的,在优化大规模的动规问题的时候有极大效果. 一般比较凶残的计数动规题都需要FFT(n<=1e9). 下面是高精度乘法 ...

  3. UVa 11572 唯一的雪花(优化策略)

    题目描述: 输入一个长度为n(n<=1000000)的序列A, 找到一个尽量长的连续子序列A(L)-->A(R),是的该序列中没有相同的元素. 输入: T:代表组数 n:代表有n个数 这一 ...

  4. HDU2586 How far away? —— 倍增LCA

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 How far away ? Time Limit: 2000/1000 MS (Java/Ot ...

  5. Java 使用POI操作EXCEL及测试框架搭建、测试开发的一些想法

    无论是UI自动化测试还是接口自动化测试都需要进行数据驱动,一般很常见的一种方式就是用excel来管理数据,那么就涉及到一些代码对EXCEL的操作,之前我们介绍过用CSV来处理EXCEL,但是它的功能还 ...

  6. 脚踏实地学C#3-装箱和拆箱

    装箱:一种接受值类型的值,根据这个值在堆中创建一个完整的引用类型对象并返回对象的引用(堆地址)的隐式转换 int i_number = 2; //在栈中声明int类型i_Number变量并初始化 ob ...

  7. 值域线段树 (玲珑OJ 1117)

    点击打开题目链接 题目意思很简单: 1.插入x 2.把小于x的数变成x 3.把大于x的数变成x 4.求集合中第x小数 5.求集合中小于x的数个数 思路: 线段树,节点是值的分数,你可以离散,也可以不离 ...

  8. H3C-端口镜像

    本地端口镜像配置举例 配置Switch: <Sysname> system-view [Sysname] mirroring-group 1 local # 创建本地镜像组 [Sysnam ...

  9. 【CQ18高一暑假前挑战赛4】标程

    [二分或者STL] 二分: #include<bits/stdc++.h> using namespace std; ; int a[maxn]; int main() { ,pos; s ...

  10. Win32编程点滴3 - 简单ActiveX控件的使用

    虽然这里一片的.net气氛,到处充斥着像MVC.WPF.WorkFlow.LINQ等各种niubility的术语.但我们使用的Windows还是由COM技术主宰着:我们在选择日常使用的软件时,也会避免 ...