我有一个类应该有一个同一个类的私有成员,如:
class A {
private:
A member;
}
但它告诉我成员是一个不完整的类型。为什么?如果我使用指针,它不会告诉我不完整的类型,但我宁愿不使用指针。任何帮助表示赞赏
答案 0 :(得分:39)
在您声明您的成员时,您仍然定义 A
类,因此类型A
仍未定义。
但是,当您编写A*
时,编译器已经知道A
代表类名,因此“指向A”的类型是已定义。这就是为什么你可以嵌入指向你正在定义的类型的指针。
同样的逻辑也适用于其他类型,所以如果你只写:
class Foo;
您声明了类Foo,但您从未定义它。你可以写:
Foo* foo;
但不是:
Foo foo;
另一方面,如果编译器允许递归定义,那么对于类型A
,您期望什么样的内存结构?
但是,它有时在逻辑上有效,以某种方式引用同一类型的另一个实例。人们通常使用指针甚至更好:智能指针(如boost::shared_ptr
),以避免必须处理手动删除。
类似的东西:
class A
{
private:
boost::shared_ptr<A> member;
};
答案 1 :(得分:25)
这是您要实现的目标的实例:
class A {
public:
A() : a(new A()) {}
~A() { delete a; a = nullptr; }
private:
A* a;
};
A a;
Happy Stack Overflow!
答案 2 :(得分:5)
A
在其定义结束之前是“不完整的”(尽管这不包括成员函数的主体)。
其中一个原因是,在定义结束之前,无法知道A
有多大(这取决于成员大小的总和,加上其他一些东西)。您的代码就是一个很好的例子:您的类型A
由类型A
的大小定义。
显然,A
类型的对象可能不包含类型为A
的成员对象。
您必须存储指针或引用;想要存储任何一个都可能是怀疑。
答案 3 :(得分:2)
你不能在A中包含A.如果你能够这样做,并且你宣布了A a;
,那么你需要无限地引用a.member.member.member...
。你没有那么多可用的RAM。
答案 4 :(得分:1)
class A
的实例如何还包含class A
的另一个实例?
如果需要,它可以保存指向A的指针。
答案 5 :(得分:1)
当您尝试使用尚未完全定义的类时,会发生此类错误。
尝试改为使用A* member
。
答案 6 :(得分:0)
当编译器遇到代码中的A对象时,会出现问题。 编译器将触及它并设置make A的对象。虽然这样做会看到A有一个同样属于A的成员。因此,为了完成A的实例化,它现在必须实例化另一个A,并且这样做它必须实例化另一个A等等。你可以看到它最终会在没有绑定的递归中结束。因此这是不允许的。编译器确保在开始实例化类的对象之前知道所有成员的所有类型和内存需求。
答案 7 :(得分:0)
理解类A
不完整的原因的一个简单方法是尝试从编译器的角度来看待它。
除其他外,编译器必须能够计算A
对象的大小。了解大小是一个非常基本的要求,它出现在许多上下文中,例如在自动内存中分配空间,调用操作符new
和评估sizeof(A)
。但是,计算A
的大小需要知道A
的大小,因为a
是A
的成员。这导致无限递归。
编译器处理此问题的方法是在A
完全已知定义之前考虑$ ./tibemsadmin
TIBCO Enterprise Message Service Administration Tool.
Copyright 2003-2013 by TIBCO Software Inc.
All rights reserved.
Version 8.0.0 V9 6/7/2013
Type 'help' for commands help, 'exit' to exit:
。您可以声明指向不完整类的指针和引用,但不允许声明值。