“不完全类型”在具有与该类本身相同类型的成员的类中
我有一个类应该有同一个类的私有成员,例如:
class A {
private:
A member;
}
但它告诉我该成员是不完整的类型。为什么?如果我使用指针,它不会告诉我类型不完整,但我宁愿不使用指针。任何帮助表示赞赏
I have a class that should have a private member of the same class, something like:
class A {
private:
A member;
}
But it tells me that member is an incomplete type. Why? It doesn't tell me incomplete type if I use a pointer, but I'd rather not use a pointer. Any help is appreciated
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
在声明成员时,您仍在定义
A
类,因此类型A
仍未定义。但是,当您编写
A*
时,编译器已经知道A
代表类名,因此“指向 A 的指针”类型已定义。这就是为什么您可以嵌入指向您定义的类型的指针。同样的逻辑也适用于其他类型,因此如果您只编写:
您声明了类 Foo,但从未定义它。您可以写:
但不能写:
另一方面,如果编译器允许递归定义,您期望类型 A 的内存结构是什么?
然而,有时在逻辑上,有一个类型以某种方式引用同一类型的另一个实例是有效的。人们通常使用指针来实现此目的,甚至更好:智能指针(如 boost::shared_ptr)以避免手动删除。
像这样的东西:
At the time you declare your member, you are still defining the
A
class, so the typeA
is still undefined.However, when you write
A*
, the compiler already knows thatA
stands for a class name, and so the type "pointer to A" is defined. That's why you can embed a pointer to the type your are defining.The same logic applies also for other types, so if you just write:
You declare the class Foo, but you never define it. You can write:
But not:
On another hand, what memory structure would you expect for your type
A
if the compiler allowed a recursive definition ?However, its sometimes logically valid to have a type that somehow refer to another instance of the same type. People usually use pointers for that or even better: smart pointers (like
boost::shared_ptr
) to avoid having to deal with manual deletion.Something like:
这是您想要实现的目标的一个工作示例:
Happy Stack Overflow!
This is a working example of what you are trying to achieve:
Happy Stack Overflow!
A
在其定义结束之前是“不完整的”(尽管这不包括成员函数的主体)。原因之一是,在定义结束之前,无法知道 A 有多大(这取决于成员大小的总和,加上其他一些因素)。您的代码就是一个很好的例子:您的类型
A
由类型A
的大小定义。显然,
A
类型的对象不能包含也是A
类型的成员对象。你必须存储一个指针或引用;想要存储其中任何一个都可能是可疑的。
A
is "incomplete" until the end of its definition (though this does not include the bodies of member functions).One of the reasons for this is that, until the definition ends, there is no way to know how large
A
is (which depends on the sum of sizes of members, plus a few other things). Your code is a great example of that: your typeA
is defined by the size of typeA
.Clearly, an object of type
A
may not contain a member object that is also of typeA
.You'll have to store a pointer or a reference; wanting to store either is possibly suspect.
理解类
A
不完整的原因的一个简单方法是尝试从编译器的角度来看待它。除此之外,编译器必须能够计算
A
对象的大小。了解大小是一个非常基本的要求,它出现在许多上下文中,例如在自动内存中分配空间、调用运算符 new 以及评估 sizeof(A) 。但是,计算A
的大小需要知道A
的大小,因为a
是A
的成员。这会导致无限递归。编译器处理这个问题的方法是认为
A
不完整,直到完全知道它的定义。您可以声明对不完整类的指针和引用,但不允许声明值。A simple way to understand the reason behind class
A
being incomplete is to try to look at it from compiler's perspective.Among other things, the compiler must be able to compute the size of
A
object. Knowing the size is a very basic requirement that shows up in many contexts, such as allocating space in automatic memory, calling operatornew
, and evaluatingsizeof(A)
. However, computing the size ofA
requires knowing the size ofA
, becausea
is a member ofA
. This leads to infinite recursion.Compiler's way of dealing with this problem is to consider
A
incomplete until its definition is fully known. You are allowed to declare pointers and references to incomplete class, but you are not allowed to declare values.您不能在 A 中包含 A。如果您能够这样做,并且您声明了,例如
A a;
,则您需要引用a.member.member.member。 .. 无限。您没有那么多可用内存。
You cannot include A within A. If you were able to do that, and you declared, for example,
A a;
, you would need to refer toa.member.member.member...
infinitely. You don't have that much RAM available.A 类
的实例如何也包含A 类
的另一个实例?如果需要的话,它可以保存指向 A 的指针。
How can an instance of
class A
also contain another instance ofclass A
?It can hold a pointer to A if you want.
当您尝试使用尚未完全定义的类时,会发生此类错误。
尝试使用
A* 成员
代替。This type of error occurs when you try to use a class that has not yet been fully DEFINED.
Try to use
A* member
instead.当编译器在代码中遇到 A 的对象时,就会出现问题。
编译器会搓手并开始创建 A 的对象。在这样做时,它将看到 A 有一个同样是 A 类型的成员。因此,为了完成 A 的实例化,它现在必须实例化另一个 A ,并且在这样做必须实例化另一个 A 等等。您可以看到它将以无限制的递归结束。因此这是不允许的。编译器在开始实例化类的对象之前,确保它知道所有成员的所有类型和内存需求。
The problem happens when the compiler comes across an object of A in code.
The compiler will rub its hand and set out make an object of A. While doing that it will see that A has a member which is again of type A. So for completing the instantiation of A it now has to instantiate another A ,and in doing so it has to instantiate another A and so forth. You can see it will end up in a recursion with no bound. Hence this is not allowed. Compiler makes sure it knows all types and memory requirement of all members before it starts instantiating an object of a class.