您好我注意到如果我在.cpp
中包含头文件,那么我可以创建该头文件类的对象。就像我在A.h
中加入main.cpp
一样,我可以在A *a;
中写main.cpp
。但是,如果我在另一个头文件中包含头文件,然后尝试创建包含头文件的对象,则这不起作用。像,
档案B.h
:
#include "A.h"
class B
{
public:
B(){};
A *a;
};
我必须添加类A
的前向声明才能使其正常工作。为什么呢?
答案 0 :(得分:13)
以下是基础知识:
对于任何类型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
,如果编译器不知道{{1的定义,则不可能}}。
请注意,类的定义意味着“类成员的完整规范,类型以及类是否具有虚函数”。如果编译器知道这些,它可以计算类的大小。
了解这些基础知识后,您可以决定是否将标题包含在其他标题中,或者只有前向声明就足够了。如果前向声明足够,那么您应该选择该选项。只有在 时才包含标题。
但是,如果您在标题A
中提供B.h
的前瞻性声明,则必须在A.h
的实施文件中包含头文件B
,即{ {1}},因为在B.cpp
的实现文件中,您需要访问编译器需要B
完整定义的A
成员。好了,只有当需要访问 A
成员时才包含。 : - )
抱歉,我没有看到你答案的最后一段。令我困惑的是为什么我也需要前瞻性声明。不包括头文件A.h单独提供A类的完整定义? -
我不知道头文件中有什么内容。此外,如果尽管包含头文件,您还需要提供前向声明,然后它暗示标头实现不正确。我怀疑存在循环依赖:
确保没有两个头文件相互包含。例如,如果A
包含A.h
,则B.h
不得直接或间接包含B.h
。
使用前向声明和指针声明来打破这种循环依赖。逻辑非常简单。如果您不能在A.h
中加入A.h
,则表示您无法在B.h
中声明A a
(因为为此,您还必须包含标题B.h
) 。因此,即使您无法声明A.h
,您仍然可以声明A a
,为此,A *pA
的前向声明就足够了。这样就可以打破循环依赖。
希望有所帮助。