This question already has answers here:
When can I use a forward declaration?

(13个回答)


3年前关闭。




我知道已经问过类似的问题,并且有答案说明在下面描述的情况下,向前声明还不够。但是,这些答案并不能说明原因。因此,我认为这不是重复的问题。

在以下情况下,我很难理解为什么编译器必须查看数据类型的定义(向前声明是不够的):

让我们考虑一下我们有一个简单的“main.cpp”,如下所示
除了包含头文件“MyClass.hpp”,绝对没有其他内容
#include <MyClass.hpp>

int main(int argc, char **argv)
{
    return 0;
}

现在,让我们考虑“MyClass.hpp”的内容如下:
#include <vector>

class Data1;

class MyClass
{
public:
    MyClass();                                      // default constructor
    MyClass(MyClass const & p_other);               // copy constructor
    MyClass(MyClass && p_other);                    // move constructor
    ~MyClass();                                     // destructor
    MyClass & operator=(MyClass const & p_rhs);     // copy assignment
    MyClass & operator=(MyClass && p_rhs);          // move assignment
private:
    Data1 *            m_a; // forward decl. always OK
    Data1              m_b; // forward decl. always not OK
    std::vector<Data1> m_c; // forward decl. OK if MyClass is not instantiated
};

MyClass包含几个成员变量:
  • “m_a”是指向“Data1”的指针
  • “m_b”是“Data1”,
  • 的实例
  • “m_c”是一个元素类型为“Data1”的 vector 。

  • “Data1”的定义既不包含在“MyClass.hpp”中,也不包含在“main.cpp”中。它只是向前声明。

    编译器永远不会对成员变量“m_a”产生问题,即使我们要实例化“MyClass”,它也不需要定义其来编译“main.cpp”。

    因为我们没有实例化“MyClass”,所以编译器的成员变量“m_c”也没有问题。在这种情况下,它也不需要定义“Data1”。

    但是,编译器存在成员变量“m_b”的问题:



    我的简单问题是:为什么?

    请考虑我们拥有用户定义的默认构造函数,复制构造函数,
    移动构造函数,用户定义的析构函数和用户定义的副本分配
    运算符和移动赋值运算符,即编译器不必
    为这些构造函数/方法中的任何一个生成代码。那是为了什么目的
    编译器仅编译“main.cpp”时需要查看“Data1”的定义吗?

    有人知道答案吗?

    最佳答案

    MyClass的大小取决于Data1的大小,只能从Data1定义知道。这就是为什么您不能在类型中使用不完整的类型作为字段。

    07-28 02:02
    查看更多