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

时间:2015-07-10 00:35:39

标签: c++ compiler-errors header-files circular-dependency

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

private ArrayList<Prayers.Prayer> activePrayers = new ArrayList<Prayers.Prayer>();

public ArrayList<Prayers.Prayer> getActivePrayers() {
    return activePrayers;
}

这似乎不是一个大问题,但为了让某些文件在逻辑上连贯,我有时会想要这种依赖。我在Visual Studio中多次遇到这个问题,同时编译C ++代码。但是,即使我为每个文件包含相应的标题保护,即

,这也永远不会编译
//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();
}

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

2 个答案:

答案 0 :(得分:4)

首先,#include是一个预处理器指令,它将一个文本文件的全文替换执行到另一个文本文件中。尝试#include的两个头文件形成嵌套文本替换的无限循环。我认为很明显,无限循环的文本替换不会“起作用”,只是因为它是无限

其次,在头文件中使用#ifndef包含警卫只会在某个时刻打破无限循环。即循环包含将变为顺序包含,首先包含一个文件,第二个包含另一个文件。但顺序包含(以任何顺序)将无助于解决头文件中存在的任何循环声明依赖性

由于这个原因,无论你是否使用包含保护,循环包含头文件都没有任何意义(除了形成非常特殊的上下文,如预处理器技巧)。循环包含从未实现任何目标。您必须设计头文件,以便他们甚至不会尝试依赖循环包含。即你必须将你的声明和头文件分层为更低级别和更高级别的文件,并始终包括更低(但不是相反),并通过在较低级别使用前向声明来解决任何循环声明依赖性头。

有时头文件只是因为它们的设计很差而需要循环包含。例如,即使声明之间没有循环依赖关系,这些声明也可能在头文件之间错误地分布,导致需要将标题彼此包含在循环中。在这种情况下,重构标题总是更好的想法,以消除任何循环声明依赖性。例如。重新分配标题之间的声明,将两个相互依赖的标题的部分提取到第三个较低级别的标题等。只有当这种重构不可能时,即你有一个真正的循环声明依赖,才使用forward-declarations作为最后的手段。 / p>

答案 1 :(得分:1)

当您在Header1.h中加入Header2.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++?

所建议的那样