例如,我想要两个头文件,它们可以依赖于另一个头文件中的函数。
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();
}
为什么不允许这样做?或者,是否有一些方法可以编译它以便它可以工作?
答案 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++?
所建议的那样