【问题标题】:Why is a forward declaration not enough even if the data type is never used [duplicate]为什么即使从未使用过数据类型,前向声明也不够[重复]
【发布时间】:2017-07-20 20:31:53
【问题描述】:

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

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

假设我们有一个简单的“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”类型元素的向量。

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

编译器对成员变量“m_a”从来没有问题,它不需要定义它来编译“main.cpp”——即使我们将实例化“MyClass”。

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

但是,编译器对成员变量“m_b”有问题:

Impl1.hpp:16:24:错误:字段“m_b”的类型“Data1”不完整

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

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

有人知道答案吗?

【问题讨论】:

  • 提示:想想sizeof(MyClass) :)
  • 我认为这不能回答我的问题。我已经阅读了现有的问题及其答案。为什么在这个例子中需要 sizeof(MyClass) ? main.cpp 完全是空的,什么都不做!
  • @A.Schorr:简而言之,MyClass 的布局必须在定义时而不是使用时已知。一旦你定义了它,即使它从未使用过,它的布局也必须是已知的。
  • main.cpp 不为空。您包括了 MyClass.hpp。这意味着 MyClass.hpp 的整个文本都包含在 main.cpp 中。它什么都不做,就像一个很长的算法什么都不返回,什么也不做。这并不意味着允许该算法使用未定义的内容。
  • 它创建了你的类。没有对象,但有类本身。其中一部分是定义一组类型作为关联的数据持有者。它看到 Data1* 并认为“好的,我需要一个指针变量,所以我添加 64 位(假设是 64 位系统),没问题。”然后它查看 vector 并认为自己“嘿,让我们问一下 vector,它需要什么”,vector 回答并且本身没有问题,因为它管理指向 Data1 本身的指针。然后它看到 Data1 并想“好的,现在,我的捆绑包需要多少存储空间来存储 Data1?”,然后询问 Data1,但没有得到任何回答。

标签: c++


【解决方案1】:

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

【讨论】:

  • 对上述答案的一些评论:为什么编译器需要知道 MyClass 的大小?它从未在任何地方使用!
  • 因为它正在编译你要求它编译的代码
猜你喜欢
  • 1970-01-01
  • 2019-10-10
  • 2018-07-19
  • 2015-04-10
  • 1970-01-01
  • 1970-01-01
  • 2016-02-16
  • 1970-01-01
  • 2017-06-18
相关资源
最近更新 更多