为什么头文件 Head1.h 不能包含包含 Head1.h 的头文件 Head2.h?

Why can't a header file Head1.h include a header file Head2.h that includes Head1.h?

例如,我想要两个头文件,它们可以依赖于另一个头文件中的函数。

//Header1.h file
#include Header2.h
void h1(){
  //...
  func1();
}
void h2();

//Header2.h file
#include Header1.h
void func1();
void func2(){
  //some other code...
  h2();
}

这似乎不是什么大问题,但为了让一些文件在逻辑上连贯,我有时需要这种依赖。在编译 C++ 代码时,我 运行 在 Visual Studio 中多次遇到这个问题。但是即使我为每个文件包含各自的头文件保护,这也永远不会编译,即

#ifndef HEADER1_H
#define HEADER1_H
//Header1.h...
#endif

为什么不允许这样做?或者,有什么方法可以编译它以便它能工作吗?

首先,#include 是一个 预处理器 指令,它执行将一个文本文件 完全文本替换 到另一个文本文件。两个 header 文件试图 #include 彼此形成嵌套文本替换的无限循环。我认为很明显,文本替换的无限循环不会 "work",仅仅因为它是 无限 .

其次,在 header 文件中使用 #ifndef include guards 会在某些时候简单地打破无限循环。 IE。循环包含将变成 顺序 包含,首先包含一个文件,然后包含另一个文件。但是顺序包含(以任何顺序)无助于解决 header 文件中存在的任何循环 声明依赖关系

出于这个原因,循环包含 header 文件从来没有任何意义(除了非常特殊的上下文,例如预处理器技巧),无论您是否使用 include guards。循环包含永远不会取得任何成就。您必须设计 header 文件,使它们甚至不会尝试依赖循环包含。 IE。你必须将你的声明和你的 header 文件分层为 lower-level 和 higher-level 文件,并且总是将较低的包含到较高的(而不是相反),并解决任何循环声明依赖在 lower-level headers.

中使用 forward-declarations

有时 header 文件要求循环包含只是因为它们设计不当。例如,即使声明之间没有循环依赖关系,这些声明也可能在 header 文件之间不正确地分布,导致人们认为需要循环地将 header 包含到彼此中。在这种情况下,重构您的 header 以消除任何循环声明依赖性总是一个更好的主意。例如。在 header 之间重新分配声明,将两个相互依赖的 header 的部分提取到第三个 lower-level header 等中。并且仅当无法进行此类重构时,即您有一个真正的循环声明依赖,使用 forward-declarations 作为最后的手段。

当您在 Header2.h 中包含 Header1.h 时,您正在创建循环依赖,反之亦然。您可以通过以下两种方式之一解决它:

1) 移动.cpp文件中每个函数的定义:

//Header1.h file
void h1();
void h2();

//Header2.h file
void func1();
void func2();

//my1.cpp file
#include Header1.h
#include Header2.h
void h1(){
  //...
  func1();
}
void h2() {
}

//my2.cpp file
#include Header1.h
#include Header2.h
void func1() {
}
void func2(){
  //some other code...
  h2();
}

2) 正如@Miki checkout 所建议的 What are forward declarations in C++?