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

时间:2018-10-31 23:40:27

标签: c++ header-files

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

4 个答案:

答案 0 :(得分: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);
[...]

...并最终得到针对每种数据类型实现的容器“类”及其相关方法,而不必每次都手动编写容器“类”的新实现。

是的,这非常丑陋-但不像必须手动写出数千行冗余容器代码那样丑陋。 (真正的容器实现头文件实现了一个哈希表,长度为几百行)

答案 1 :(得分:4)

一旦编译器必须维护包含文件的列表,就无需包含保护或#pragma。这并不容易,因为这些文件的路径可能不同(并且#pragma曾经无法完全解决这个问题),并且期望使用很多原始C编译器,而这些C编译器必须使用非常有限的内存。

答案 2 :(得分:2)

当C出现并且创建C预处理程序所基于的C预处理程序时,今天的真实情况并不一定正确。

#pragma once仅是拥有适当C++ modules的一步,因此,这种令人讨厌的历史遗产最终被消除了。

是的,多次包含文件是有效的,是的,每次包含文件时,文件的行为都可能完全不同。这就是为什么对编译器开发人员来说,制作预编译的头文件会非常麻烦。

答案 3 :(得分:2)

包含保护块或#pragma once,以防止多次包含文件。

#pragma once虽然在大多数编译器上都受支持,但不是c ++标准的正式组成部分,并且可能不适用于所有编译器。您可以使用保护块,该保护块可在任何编译器上使用。文件MyClass.hpp中的保护块示例为:

#ifndef MYCLASS_HPP
#define MYCLASS_HPP

//Code here

#endif