#include<iostream.h>
class A
{
A a;
};
int main()
{
A a;
return 0;
}
为什么编译器说“a”的类型不完整? 但是在java递归中发生..plz解释它。?
答案 0 :(得分:5)
在C ++中,A a
表示类型为A
的对象,而不是指向位于其他位置的某个对象的引用或指针。必须知道A
的定义才能做出这样的陈述,除其他外,这意味着必须完全确定A
的大小。
当您尝试将类型的实例作为相同类型的成员时,您将获得无限递归。该语言完全不允许这样做,声明任何类型的数据成员必须是完整类型,这意味着它的定义必须是可用的。
另一方面,这是允许的,并且更接近java语义:
class A { A* a; };
class B { B& b; };
有关详细信息,请参阅此相关帖子:When to use forward declaration?
答案 1 :(得分:2)
这两者并不相同。当您使用Java命名对象时,实际上是在命名引用,因此C ++中的等效代码是:
class A
{
A& a;
};
或者,可以说:
class A
{
A* a;
};
这些都非常有效。
另一方面,尝试存储A
类型的值显然不起作用。 Java只是没有语法来尝试这一点,但C ++确实 - 并且不完整类型规则阻止你陷入其中。
答案 2 :(得分:2)
在C ++中,你需要一个与它所在类相同类型的成员。这是不允许的,因为你需要知道对象的大小来创建内存布局来分配它,它可能会有所改变像这样:
- what's the size of A?
- it contains an object of class A.. what's the size of this object?
- what's the size of A?
- it contains.. bla bla bla
并且你最终会有一个没有任何意义的无限递归。这是不允许的。您可以使用引用或指针解决问题,但这与您提出的解决方案不同。
在Java中,语法是允许的,因为它没有实例化类型(它是引用),但是如果你尝试实例化那么行为是相同的
public class myClass {
private myClass p = new myClass(); // Runtime error!!
public static void main(String[] args) {
new myClass();
}
}
有一点需要注意:Java不会在编译时捕获它,而只是在运行时捕获(因此耗尽VM的内存,除非在此之前未检测到此机制),而C ++设法在编译时捕获它
答案 3 :(得分:1)
如果我们转到draft C++ standard,我们可以看到在结束}
之前未完全定义某个类,这是在9.2
类成员部分中段落 2 :
在classspecifier的close}处,类被视为完全定义的对象类型(3.9)(或完整类型)。 [...]
并且类的所有非静态数据成员必须完整,在 9 段落中
非静态(9.4)数据成员不得有不完整的类型。特别是,C类不得包含 C类的非静态成员,但它可以包含指向C类对象的指针或引用。
但正如它所说它可以包含一个指针或一个更接近Java如何做的引用。