c++ - 为什么一定要Forward声明一个类,在一个头文件中包含对应的头文件

标签 c++ class header-files forward-declaration

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

文件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*)只是该平台上指针的大小(通常在 32 位系统上为 4 字节或在 64 位系统上为 8 字节)。

  • 对于任何类型 A ,如果你声明一个 A 类型的变量, A[N] , A[M]N]等,然后编译器需要知道类型的完整定义 A在变量声明的地方。在这种情况下,前向声明(forward declaration)是不够的。

    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 的定义,这是不可能的.

    请注意,类的定义 表示“类成员、它们的类型以及类是否具有虚函数的完整规范”。如果编译器知道这些,它就可以计算出类的大小。

了解这些基础知识后,您可以决定是将 header 包含到其他 header 中,还是仅前向声明就足够了。如果前向声明就足够了,那就是您应该选择的选项。包含 header 仅当需要时。

但是,如果您提供 A 的前向声明在标题中 B.h , 那么你必须包含头文件 A.hB的实现文件中这是B.cpp , 因为在 B 的实现文件中,您需要访问 A 的成员为此,编译器需要 A 的完整定义.再次重申,仅当需要访问 A 的成员时才包括在内. :-)


Sorry I didn't see the last paragraph of your answer. What is confusing me is why do I need the forward declaration also. Doesn't including the header file A.h alone provides complete definition of class A?? –

不知道头文件里有什么。另外,如果尽管包含头文件,您还需要提供前向声明,那么它暗示头文件实现不正确。我怀疑存在循环依赖:

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

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

希望对您有所帮助。

关于c++ - 为什么一定要Forward声明一个类,在一个头文件中包含对应的头文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14413403/

相关文章:

C++随机生成的字典单词只会显示以B开头的单词

java - 获取运行时创建的类

c# - 递归类的最佳实践

c++ - 根据模板的类型名设置私有(private)属性

c++ - 如何将 C++ 程序分解为模块

c++ - 什么是 C++ 中头文件的保护 block ?

c++ - 使用 boost::property_tree 选择一个子节点标签而不考虑位置

c++ - 多个实例持有对 unique_ptr 的引用

c++ - 如何编译c++而不包括cstdio和其他c标准库

c++ - 给定一个源文件,有没有办法让 gcc 只返回直接包含的头文件列表?