【问题标题】:"Incomplete type" in class which has a member of the same type of the class itself类中具有与类本身相同类型的成员的“不完整类型”
【发布时间】:2011-09-15 01:01:40
【问题描述】:

我有一个类应该有同一个类的私有成员,例如:

class A {
    private:
        A member;
}

但它告诉我 member 是不完整的类型。为什么?如果我使用指针,它不会告诉我不完整的类型,但我宁愿不使用指针。任何帮助表示赞赏

【问题讨论】:

  • 如果您的操作被允许,A 的实例需要多少字节?
  • 你这里还有一个问题。私有A 将有它自己的私有成员,它有它自己的私有成员,它有...
  • Incomplete Type 的可能重复项
  • @BoPersson:几乎没有重复,尽管两个 OP 的错误是相同的。
  • @Tomalak - 他们都试图拥有具有相同类型成员的类,并得到相同的错误消息。可能意图不同,但结果相同。

标签: c++ types member private-members incomplete-type


【解决方案1】:

在您声明您的成员时,您仍在定义A 类,因此A 类型仍未定义。

但是,当您编写A* 时,编译器已经知道A 代表类名,因此“指向A 的指针”类型是定义。这就是为什么您可以嵌入一个指向您正在定义的类型的指针。

同样的逻辑也适用于其他类型,所以如果你只是写:

class Foo;

您声明了类 Foo,但您从未定义它。你可以写:

Foo* foo;

但不是:

Foo foo;

另一方面,如果编译器允许递归定义,您希望类型 A 的内存结构是什么?

但是,有时在逻辑上,有一个类型以某种方式引用同一类型的另一个实例。人们通常为此使用指针,甚至更好:智能指针(如boost::shared_ptr)以避免手动删除。

类似:

class A
{
  private:
    boost::shared_ptr<A> member;
};

【讨论】:

  • 我正在制作一个迷宫解决程序,我希望班级职位有一个以前的职位成员。
  • @Sterling:我已经更新了我的答案以指出可能的解决方案。
  • @Sterling:owning 类同时包含“nowPosition”和“previousPosition”成员可能更有意义。一个职位就是一个职位;它不需要知道其他职位。
  • @CrazyPython Python 之所以允许这样做是因为它使用引用,这相当于我提到的shared_ptr 解决方案。请注意,这样做通常会导致循环引用问题,这可能会阻止垃圾收集完成其工作,因此它也不是灵丹妙药。
【解决方案2】:

这是您想要达到的目标的一个工作示例:

class A {
public:
    A() : a(new A()) {}
    ~A() { delete a; a = nullptr; }
private:
    A* a;
};

A a;

堆栈溢出快乐!

【讨论】:

  • 请删除内部A* a。关于阶级毁灭。我们不需要教年轻程序员比他们自己做的更多的内存泄漏示例。
  • 实际上,这是在堆上分配的,所以无论先发生什么,它都会引发堆栈溢出和内存不足错误。
【解决方案3】:

A 在其定义结束之前是“不完整的”(尽管这不包括成员函数的主体)。

其中一个原因是,在定义结束之前,无法知道A 有多大(这取决于成员大小的总和,以及其他一些因素)。您的代码就是一个很好的例子:您的 A 类型由 A 类型的大小定义。

显然,A 类型的对象可能不包含同样是 A 类型的成员对象。

您必须存储指针或引用;想要存储任何一个都可能是可疑的。

【讨论】:

    【解决方案4】:

    了解 A 类不完整背后的原因的一个简单方法是尝试从编译器的角度来看待它。

    除其他外,编译器必须能够计算A 对象的大小。知道大小是一个非常基本的要求,在许多情况下都会出现,例如在自动内存中分配空间、调用运算符new 和评估sizeof(A)。但是,计算A 的大小需要知道A 的大小,因为aA 的成员。这会导致无限递归。

    编译器处理这个问题的方法是认为A 是不完整的,直到它的定义被完全知道。允许声明指向不完整类的指针和引用,但不允许声明值。

    【讨论】:

      【解决方案5】:

      您不能在 A 中包含 A。如果您能够做到这一点,并且您声明了 A a;,则您需要无限引用 a.member.member.member...。你没有那么多可用的内存。

      【讨论】:

        【解决方案6】:

        class A 的实例如何也包含class A 的另一个实例?

        如果你愿意,它可以持有指向 A 的指针。

        【讨论】:

          【解决方案7】:

          当您尝试使用尚未完全定义的类时会发生此类错误。

          尝试改用A* member

          【讨论】:

            【解决方案8】:

            当编译器在代码中遇到 A 的对象时,就会出现问题。 编译器将揉搓它的手并着手创建一个 A 的对象。在这样做的同时,它会看到 A 有一个再次属于 A 类型的成员。因此,为了完成 A 的实例化,它现在必须实例化另一个 A ,并且在这样做它必须实例化另一个 A 等等。你可以看到它会以一个没有限制的递归结束。因此这是不允许的。编译器确保它在开始实例化一个类的对象之前知道所有成员的所有类型和内存要求。

            【讨论】:

              最近更新 更多