我大致了解它的作用。我不明白的是为什么它不是默认值?在哪些情况下需要多次包含某些头文件?
答案 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