c++头文件相互包含
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8526819/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
c++ header files including each other mutually
提问by MegaManX
I have two classes both defined in separate header files. Each file has a field that is type of other class. Now I included in header of each file the header of other file, but compiler is generating errors. What am i missing?
我有两个类都定义在单独的头文件中。每个文件都有一个属于其他类的字段。现在我在每个文件的头文件中包含了其他文件的头文件,但是编译器产生了错误。我错过了什么?
回答by Mike Nakis
You cannot have each class have "a field that is type of other class"; that would be a recursive definition and not only the compiler would not be able to make any sense out of it, it does not even make logical sense.
你不能让每个班级都有“一个属于其他班级的字段”;这将是一个递归定义,不仅编译器无法理解它,它甚至没有逻辑意义。
Each class having a field that is type of the other class is the kind of impossibility that you only see in M.C. Escher drawings, or animations thereof, like this one:
每个类都有一个属于另一个类的类型的字段,这是您只能在 MC Escher 绘图或其动画中看到的那种不可能性,如下所示:
B. de Smit and H. W. Lenstra - Source: escherdroste.math.leidenuniv.nl
B. de Smit 和 HW Lenstra - 来源:escherdroste.math.leidenuniv.nl
based on Escher's "Print Gallery" Lithograph, 1956, see Wikipedia
基于埃舍尔的“印刷画廊”石版画,1956 年,参见维基百科
One of the two fields will have to be a pointer, so as to break the recursive containment, and avoid the logical impossibility.
这两个字段之一必须是一个指针,以打破递归包含,避免逻辑上的不可能性。
Which brings us to the next problem: if class B is to contain an instance of class A, then obviously, A has to be declared before class B, so that A is already known to the compiler when compiling B. But if class A is declared before class B, how can we declare a pointer to B in A? Class B is not known yet at the time that A is compiled! The answer to this is a special construct known as forward declarationwhich exists precisely in order to accommodate situations like this. A forward declaration of class B looks like this:
这给我们带来了下一个问题:如果类 B 要包含类 A 的实例,那么显然必须在类 B 之前声明 A,以便编译器在编译 B 时已经知道 A。但是如果类 A 是在类 B 之前声明,我们如何在 A 中声明指向 B 的指针?在 A 被编译时,B 类还不知道!对此的答案是一种称为前向声明的特殊结构,它的存在正是为了适应这种情况。B 类的前向声明如下所示:
class B;
All it is telling the compiler is that there will be a class called B. It does not tell the compiler anything about the contents of class B, so there is very little we can do with it, but we can do one thing: declare pointers to B.
它只是告诉编译器将有一个名为 B 的类。它不会告诉编译器有关 B 类内容的任何信息,因此我们对它几乎无能为力,但我们可以做一件事:声明指针到 B。
So, the full solution to the problem looks like this:
因此,该问题的完整解决方案如下所示:
file "A.h":
文件“啊”:
/* This is called a "forward declaration". We use it to tell the compiler that
the identifier "B" will from now on stand for a class, and this class will be
defined later. We will not be able to make any use of "B" before it has been
defined, but we will at least be able to declare pointers to it. */
class B;
class A
{
/* We cannot have a field of type "B" here, because it has not yet been
defined. However, with the forward declaration we have told the compiler
that "B" is a class, so we can at least have a field which is a pointer
to "B". */
B* pb;
}
file "B.h":
文件“Bh”:
#include "A.h"
class B
{
/* the compiler now knows the size of "A", so we can have a field
of type "A". */
A a;
}
回答by Matt Lacey
You shouldn't include the header files inside the other ones, just include the header files in your source files.
您不应该在其他文件中包含头文件,只需在源文件中包含头文件即可。
In the headers you can use a forward declaration:
在标题中,您可以使用前向声明:
// In Class1.h
class Class2;
// In class2.h
class Class1;
Also you can protect against a file being included twice using the preprocessor:
您还可以使用预处理器防止文件被包含两次:
// Class1.h
#ifndef __CLASS_1_H
#define __CLASS_1_H
// content
#endif
回答by Boynux
I know this is an old topic but maybe you are still interested in solution!
我知道这是一个古老的话题,但也许您仍然对解决方案感兴趣!
Actually in C++ you can use two classes recursively without using pointers and here is how to do it.
实际上,在 C++ 中,您可以在不使用指针的情况下递归地使用两个类,这是如何做到的。
file: a.h
档案:啊
#include <b.h>
class A {
B<> b;
}
file: b.h
文件:bh
class A;
template<typename T = A>
class B {
T a;
}
file: main.cpp
文件:main.cpp
#include "a.h"
A a;
and that's all!
就这样!
of course this is just for curiosity :)
当然这只是出于好奇:)
回答by Michael Krelin - hacker
You probably want to use forward declaration, unless you actually want to put instance of each class in each other. In which case you shouldn't use anything.
您可能想使用前向声明,除非您真的想将每个类的实例放在一起。在这种情况下,您不应该使用任何东西。
回答by a.l.e
If B can only exist within A, I seem to be able to create A and B without using a pointer. B has to simply forward declare A and not include it (avoiding the recursive inclusion).
如果 B 只能存在于 A 中,我似乎可以在不使用指针的情况下创建 A 和 B。B 必须简单地转发声明 A 而不是包含它(避免递归包含)。
In my case, a Document
has a Section
which gets a reference to its Document
.
在我的例子中, aDocument
有Section
一个引用它的Document
.
section.h
section.h
class Document;
class Section
{
public:
Section(Document& document) : document{document} {}
private:
Document& document;
};
document.h
document.h
#include "section.h"
class Document
{
public:
Document() : section{*this} {}
private:
Section section;
};
main.cpp
main.cpp
#include "document.h"
int main()
{
Document document{};
}
This code compiles with g++
and runs on Linux.
此代码g++
在 Linux 上编译并运行。
A (complex) set of ifdef
might enable it for other cases, but I'm not sure about the readability...
一组(复杂的)ifdef
可能会在其他情况下启用它,但我不确定可读性......
回答by Thomas_M
Besides the possibility of forward declaration - if it seems that you need two classes mutually within the other it is out of my experience a sign for a mistake in the depth of inheritance. Eather the classes are a kind of siblings and you should create a parent class for both. Or you are trying to use a class that is in fact a parent class within one that should have a sibling from this parent class. Then you should create this sibling as a third class.
除了前向声明的可能性 - 如果您似乎需要在另一个类中相互使用两个类,那么根据我的经验,这是继承深度错误的标志。这些类是一种兄弟姐妹,您应该为两者创建一个父类。或者您正在尝试使用一个实际上是父类中的类,该类应该具有来自该父类的兄弟。然后你应该创建这个兄弟作为第三个类。