嗨,我注意到如果我在 a 中包含一个头文件,.cpp
那么我可以创建该头文件类的一个对象。就像如果我包括在内A.h
,main.cpp
那么我可以写A *a;
在main.cpp
. 但是,如果我在另一个头文件中包含一个头文件,然后尝试创建包含的头文件的对象,这将不起作用。像,
文件B.h
:
#include "A.h"
class B
{
public:
B(){};
A *a;
};
我必须添加类的前向声明A
才能使其工作。为什么?
嗨,我注意到如果我在 a 中包含一个头文件,.cpp
那么我可以创建该头文件类的一个对象。就像如果我包括在内A.h
,main.cpp
那么我可以写A *a;
在main.cpp
. 但是,如果我在另一个头文件中包含一个头文件,然后尝试创建包含的头文件的对象,这将不起作用。像,
文件B.h
:
#include "A.h"
class B
{
public:
B(){};
A *a;
};
我必须添加类的前向声明A
才能使其工作。为什么?
以下是基础知识:
对于任何类型A
,如果你声明了一个 , , , 等类型的变量A&
,A*
那么A**
编译A***
器不需要知道A
变量声明处的完整定义。它只需要知道A
一个类型;这就对了。所以一个前向声明就足够了:
class A; //forward declaration
class B
{
A * pA; //okay - compiler knows A is a type
A & refA;/ okay - compiler knows A is a type
};
不需要 完整的定义,因为编译器仍然可以计算sizeof(B)
哪个反过来依赖于sizeof(A*)
和sizeof(A&)
- 这些对于编译器来说是已知的,即使它不知道 sizeof(A)
。请注意,这sizeof(A*)
只是该平台上的指针大小(通常 4
是 32 位系统上的8
字节或 64 位系统上的字节)。
对于任何类型A
,如果你声明了一个类型为 , 等的变量A
,A[N]
那么A[M]N]
编译器需要A
在变量声明的地方知道类型的完整定义。在这种情况下,前向声明是不够的。
class A; //forward declaration
class B
{
A a; //error - the compiler only knows A is a type
//it doesn't know its size!
};
但这是正确的:
#include "A.h" //which defines A
class B
{
A a; //okay
};
需要完整的定义, 以便编译器可以计算,如果编译器不知道 的定义,这是不可能的。sizeof(A)
A
请注意,类的定义是指“类成员、它们的类型以及类是否具有虚函数的完整规范”。如果编译器知道这些,它可以计算类的大小。
了解这些基础知识后,您可以决定是否将标头包含到其他标头中,或者仅前向声明就足够了。如果前向声明就足够了,那是您应该选择的选项。仅在需要时才包含标题。
但是,如果你在头文件中提供前向声明A
,B.h
那么你必须将头文件包含A.h
在它的实现文件中B
,B.cpp
因为在的实现文件中B
,你需要访问A
编译器需要完整定义的成员。 A
. 同样,仅当您需要访问. A
:-)
对不起,我没有看到你答案的最后一段。令我困惑的是为什么我还需要前向声明。不包括头文件Ah单独提供了A类的完整定义吗?——</p>
我不知道头文件中有什么。另外,如果尽管包含了头文件,但还需要提供前向声明,则意味着头文件实现不正确。我怀疑存在循环依赖:
确保没有两个头文件相互包含。例如,如果A.h
包含B.h
,则B.h
不得A.h
直接或间接包含。
Use forward declaration and pointer-declaration to break such circular dependency. The logic is pretty much straight-forward. If you cannot include A.h
in B.h
, which implies you cannot declare A a
in B.h
(because for this, you have to include the header A.h
also). So even though you cannot declare A a
, you can still declare A *pA
, and for this a forward declaration of A
is enough. That way you break the circular dependency.
Hope that helps.