C++ 是否包含包含的头文件包含的所有头文件?
Does C++ include all headers a included header file includes?
在这个示例代码中,我有 3 个文件:
testHeader.h:
void hello() { }
file1.h:
#include "testHeader.h"
#include <iostream>
void sayHi() { std::cout << "hi" << std::endl; }
file2.h:
#include "file1.h"
void sayHello() { std::cout << "hello" << std::endl; }
如果 file1.h
包含 testHeader.h
且 file2.h
包含 file1.h
,testHeader.h
及其功能是否可以在 file2.h
中访问? <iostream>
及其函数呢?
除非以奇怪的方式受到预处理器守卫的保护,是的,你得到了它们。 #include
很大程度上是一个预处理器技巧,大致相当于将包含的文本转储到源代码中,并且它是可传递的;如果你 #include <a.h>
,你会得到 a.h
的扩展形式,包括它的所有包含的预处理器扩展形式,它们的所有包含等等,等等,无限,在一次通过中。
请注意,明确包含您直接依赖的所有内容仍然是个好主意;当然,其他 .h
文件今天可能 #include <vector>
,但如果它们不是公开的 API 的必要部分,则不能保证下一个版本会有它们。
还值得注意的是,预处理器包含防护 (and/or #pragma once
) 几乎普遍用于表示 .h
文件的内容不会被包含两次(按照惯例,不是保证;如果 .h
文件写得不好,或者设计用于多次包含不同预处理器设置的怪异文件,则不会遵守); re-including 在 .cpp
中的 header 几乎没有成本,它已经从您包含的 .h
中获得。在较旧的编译器上,没有 #pragma once
并且没有对包含守卫的特殊处理,它可能必须第二次加载 header ,查看守卫,并且在第二次包含时不转储任何内容;许多较新的编译器足够聪明,甚至可以避免这种成本。重点是,不要试图通过避免冗余 #include
s 来进行优化;每个文件都应该包含该文件中所用内容所需的完整 #include
集,不多也不少。
如果您使用较旧的编译器,没有#pragma once,请尝试执行以下操作。
--- file1.h ---
#ifndef FILE1_H
#define FILE1_H
#include "testHeader.h"
#include <iostream>
void sayHi();
#endif
--- file1.cpp ---
#include "file.h"
void sayHi() { std::cout << "hi" << std::endl; }
--- file2.h ---
#ifndef FILE2_H
#define FILE2_H
#include "file1.h"
#include <iostream>
void sayHello();
#endif
你不应该在 HEADER 文件中创建函数体。对于同一功能的多个链接,它可能会导致编译错误。请将函数的原型和函数体分别写到Header和Source文件中。
在这个示例代码中,我有 3 个文件:
testHeader.h:
void hello() { }
file1.h:
#include "testHeader.h"
#include <iostream>
void sayHi() { std::cout << "hi" << std::endl; }
file2.h:
#include "file1.h"
void sayHello() { std::cout << "hello" << std::endl; }
如果 file1.h
包含 testHeader.h
且 file2.h
包含 file1.h
,testHeader.h
及其功能是否可以在 file2.h
中访问? <iostream>
及其函数呢?
除非以奇怪的方式受到预处理器守卫的保护,是的,你得到了它们。 #include
很大程度上是一个预处理器技巧,大致相当于将包含的文本转储到源代码中,并且它是可传递的;如果你 #include <a.h>
,你会得到 a.h
的扩展形式,包括它的所有包含的预处理器扩展形式,它们的所有包含等等,等等,无限,在一次通过中。
请注意,明确包含您直接依赖的所有内容仍然是个好主意;当然,其他 .h
文件今天可能 #include <vector>
,但如果它们不是公开的 API 的必要部分,则不能保证下一个版本会有它们。
还值得注意的是,预处理器包含防护 (and/or #pragma once
) 几乎普遍用于表示 .h
文件的内容不会被包含两次(按照惯例,不是保证;如果 .h
文件写得不好,或者设计用于多次包含不同预处理器设置的怪异文件,则不会遵守); re-including 在 .cpp
中的 header 几乎没有成本,它已经从您包含的 .h
中获得。在较旧的编译器上,没有 #pragma once
并且没有对包含守卫的特殊处理,它可能必须第二次加载 header ,查看守卫,并且在第二次包含时不转储任何内容;许多较新的编译器足够聪明,甚至可以避免这种成本。重点是,不要试图通过避免冗余 #include
s 来进行优化;每个文件都应该包含该文件中所用内容所需的完整 #include
集,不多也不少。
如果您使用较旧的编译器,没有#pragma once,请尝试执行以下操作。
--- file1.h ---
#ifndef FILE1_H
#define FILE1_H
#include "testHeader.h"
#include <iostream>
void sayHi();
#endif
--- file1.cpp ---
#include "file.h"
void sayHi() { std::cout << "hi" << std::endl; }
--- file2.h ---
#ifndef FILE2_H
#define FILE2_H
#include "file1.h"
#include <iostream>
void sayHello();
#endif
你不应该在 HEADER 文件中创建函数体。对于同一功能的多个链接,它可能会导致编译错误。请将函数的原型和函数体分别写到Header和Source文件中。