问题描述
||
我有一个班级,应该有一个属于同一班级的私人成员,例如:
class A {
private:
A member;
}
但这告诉我成员是不完整的类型。为什么?如果使用指针,它不会告诉我类型不完整,但是我宁愿不使用指针。任何帮助表示赞赏
解决方法
在声明成员时,仍在定义
A
类,因此类型A
仍未定义。
但是,当您编写“ 3”时,编译器已经知道“ 1”代表类名,因此定义了类型“指向A的指针”。因此,您可以嵌入一个指向所定义类型的指针。
相同的逻辑也适用于其他类型,因此,如果您只写:
class Foo;
您声明了Foo类,但从未定义。你可以写:
Foo* foo;
但不是:
Foo foo;
另一方面,如果编译器允许递归定义,则您对类型“ 1”会期望什么存储结构?
但是,有时在逻辑上有效的是拥有某种以某种方式引用同一类型的另一个实例的类型。人们通常使用甚至更好的指针:智能指针(如boost::shared_ptr
)以避免处理手动删除操作。
就像是:
class A
{
private:
boost::shared_ptr<A> member;
};
, 这是您要实现的目标的一个有效示例:
class A {
public:
A() : a(new A()) {}
~A() { delete a; a = nullptr; }
private:
A* a;
};
A a;
快乐堆栈溢出!
, ѭ1definition在定义结束之前为“不完整”(尽管不包括成员函数的主体)。
原因之一是,在定义结束之前,无法知道A
有多大(这取决于成员大小的总和,以及其他一些事情)。您的代码就是一个很好的例子:类型A
由类型A
的大小定义。
显然,类型为“ 1”的对象可能不包含也是类型为“ 1”的成员对象。
您将必须存储一个指针或引用;想要存储任何一个都可能令人怀疑。
, 理解类“ 1”不完整的原因的一种简单方法是尝试从编译器的角度来看它。
除其他事项外,编译器必须能够计算A
对象的大小。知道大小是一个非常基本的要求,它在许多情况下都会显示出来,例如在自动存储器中分配空间,调用运算符new
和评估sizeof(A)
。但是,计算A
的大小需要知道A
的大小,因为a
是A
的成员。这导致无限递归。
编译器处理此问题的方法是,在完全知道其定义之前,先考虑A
不完整。允许您声明不完整类的指针和引用,但不允许声明值。
, 您不能在A内包含A。如果您能够做到这一点,并且例如声明了A a;
,则需要无限引用a.member.member.member...
。您没有足够的可用RAM。
, class A
的实例又如何包含class A
的另一个实例?
如果需要,它可以保存指向A的指针。
, 当您尝试使用尚未完全定义的类时,会发生此类错误。
尝试改用A* member
。
, 当编译器在代码中遇到A对象时,就会发生此问题。
编译器将揉搓手并设置一个A对象。这样做时,它将看到A具有一个再次为A类型的成员。因此,为了完成A的实例化,它现在必须实例化另一个A,并且在这样做必须实例化另一个A,依此类推。您可以看到它将以无限制的递归结束。因此,这是不允许的。编译器确保在开始实例化类的对象之前,它了解所有成员的所有类型和内存要求。