为什么我们必须转发声明一个类并在头文件中包含相应的头文件

Tah*_*lil 4 c++ class header-files forward-declaration

嗨,我注意到如果我在头文件中包含头文件,.cpp那么我可以创建该头文件类的对象.就像如果我有A.hmain.cpp那我可以写A *a;main.cpp.但是,如果我在另一个头文件中包含头文件,然后尝试创建包含头文件的对象,则这不起作用.喜欢,

档案B.h:

#include "A.h"
class B
{
public:
    B(){};
    A *a;
};
Run Code Online (Sandbox Code Playgroud)

我必须添加类的前向声明A才能使它工作.为什么?

Naw*_*waz 14

以下是基础知识:

  • 对于任何类型的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
    };
    
    Run Code Online (Sandbox Code Playgroud)

    完整的定义并不 需要,因为编译器仍然可以计算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!
    };
    
    Run Code Online (Sandbox Code Playgroud)

    但这是正确的:

    #include "A.h" //which defines A
    
    class B
    {
       A a;  //okay
    };
    
    Run Code Online (Sandbox Code Playgroud)

    完整的定义 必需的,以便编译器可以计算sizeof(A),如果编译器不知道定义,则这是不可能的A.

    请注意,类的定义意味着"类成员的完整规范,类型以及类是否具有虚函数".如果编译器知道这些,它可以计算类的大小.

了解这些基础知识后,您可以决定是否将标题包含在其他标题中,或者只有前向声明就足够了.如果前向声明足够,那么您应该选择该选项.包括头只有在它需要.

不过,如果你提供向前的声明A在标题B.h,那么你必须包含头文件A.h的实现文件的BB.cpp,由于在执行文件B,你需要访问成员A为其编译器要求的完整定义A.好了,只有当需要访问成员时才包含A.:-)


对不起,我没有看到你答案的最后一段.令我困惑的是为什么我也需要前瞻性声明.不包括头文件啊单独提供A类的完整定义? -

我不知道头文件中有什么.此外,如果尽管包含头文件,您还需要提供前向声明,那么它意味着标头实现不正确.我怀疑存在循环依赖:

  • 确保没有两个头文件相互包含.例如,如果A.h包含B.h,则B.h不得A.h直接或间接包含.

  • 使用前向声明和指针声明来打破这种循环依赖.逻辑非常简单.如果您不能包括A.hB.h,这意味着你不能声明A aB.h(因为这一点,你必须包括头A.h也).所以即使你不能声明A a,你仍然可以声明A *pA,为此,前向声明A就足够了.这样你就打破了循环依赖.

希望有所帮助.