为什么 C++ 头文件需要使用包含保护?

5

我大致了解它的作用。但我不明白为什么它不是默认设置?在什么情况下需要多次包含某个头文件?


2
建议将标题更改为使用“包含保护”短语而不是“pragma once”,因为后者是以特定于平台的方式执行前者的一种方法。 - Christopher Pisz
4个回答

8
这不是默认设置的原因主要是出于历史原因 - 当C语言被规范化时,#include指定其必须表现得完全像用户已经将指定文件的内容复制并粘贴到了#include行的位置; C ++希望(并且希望)尽可能与C兼容,因此C++从C继承了该行为。
至于多次包含相同标头文件可能有用的用例,我发现其中一个实例是在C中模拟模板化容器类(因为C不直接支持模板)。 我有一个容器实现头文件,大致如下(但更加复杂; 这里为了可读性显示了简化版):
// MyContainerImplemention.h
// be sure to #define MYTYPE and MYARRAYSIZE
// before #include-ing this file!

struct ArrayOf##MYTYPE
{
   MYTYPE arrayOfItems[MYARRAYSIZE];
};

inline void Set##MYTYPE##Item(struct ArrayOf##MyType * container, int which, MYTYPE item) 
{
   container[which] = item;
}

[... and so on for various other MYTYPE-specific methods ...]

如果这样做,那么我的 .c 文件可以做类似这样的事情:

#define MYTYPE int
#define MYARRAYSIZE 10
#include "MyContainerImplementation.h"
#undef MYARRAYSIZE
#undef MYTYPE

#define MYTYPE short
#define MYARRAYSIZE 15
#include "MyContainerImplementation.h"
#undef MYARRAYSIZE
#undef MYTYPE

struct ArrayOfint myInts;
struct ArrayOfshort myShorts;

SetintItem(&myInts, 5, 12);
SetshortItem(&myShorts, 3, 2);
[...]

...最终得到每种数据类型的“class”容器及其相关方法的实现,而无需每次手动编写新的容器“class”实现。

是的,这样做非常丑陋 -- 但不如手动编写成千上万行冗余的容器代码那么丑陋。(真正的容器实现头文件实现了一个哈希表,有几百行长)


4

如果没有包含保护或 #pragma once,编译器将不得不维护一个包含文件列表。这并不容易,因为这些文件有不同的可能路径(而 #pragma once 并不能完全解决这个问题),而原始的 C 编译器需要使用非常有限的内存。


2
今天的真相并不一定适用于C语言及其预处理器(C++预处理器基于此),这是在C语言出现以及创建C预处理器时的历史遗留问题。 #pragma once 只是迈向拥有适当的C ++模块的一步,因此可以最终消除这种令人烦恼的历史遗留问题。
是的,多次包含文件是有效的,而且每次包含文件时它都可能表现出完全不同的方式。这就是为什么制作预编译头文件对编译器开发人员来说是一个巨大的头疼问题。

2

为防止文件被多次包含,需要使用守卫块或者#pragma once

#pragma once虽然在大多数编译器上都受支持,但并非C++标准的正式部分,可能无法在所有编译器上工作。您可以使用守卫块,这将在任何编译器上都能正常工作。在MyClass.hpp文件中使用守卫块的示例如下:

#ifndef MYCLASS_HPP
#define MYCLASS_HPP

//Code here

#endif

1
虽然你提出了一个很好的观点,但这并没有真正回答所提出的问题。考虑添加一段解释为什么#pragma once或者包含保护是必要的。 - Silvio Mayolo
值得注意的是,在#ifndef中使用的标识符需要具有相当程度的唯一性。前几天我们遇到了一个问题,其中一些可怜的人在头文件中使用了类的名称,导致类名被宏替换为空字符串。#define myclass,然后稍后class myclass { ... };导致编译器看到了class { ... };,结果造成了彻底的混乱。 - user4581301

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接