为什么编译器在此代码中说不完整的类型错误

why compiler is saying Incomplete type error in this code?

本文关键字:类型 错误 说不完 编译器 代码 为什么      更新时间:2023-10-16
#include<iostream.h>
class A 
{    
   A a;            
};             
int main()       
{       
A a;              
return 0;           
}

为什么编译器说"A"的类型不完整?但是在Java中发生递归..请解释一下。?

在C++中,A a表示类型为 A 的对象,而不是指向位于其他地方的某个对象的引用或指针。必须知道A的定义才能作出这样的声明,除其他外,这意味着必须完全确定A的大小。

当您尝试将某个类型的实例作为同一类型的成员时,您将获得无限递归。该语言根本不允许这样做,声明任何类型的数据成员必须是完整类型,这意味着其定义必须可用。

另一方面,这是允许的,并且更接近Java语义:

class A { A* a; };
class B { B& b; };

有关详细信息,请参阅此相关文章:何时使用前向声明?

两者并不等同。当你在 Java 中命名一个对象时,你实际上是在命名一个引用,所以C++中的等效代码是:

class A 
{    
   A& a;
};

或者,可以说:

class A 
{    
   A* a;
};

这些都是完全有效的。

另一方面,尝试存储类型 A 的值显然是行不通的。Java根本没有语法来尝试这样做,但C++有 - 不完整的类型规则可以防止你陷入其中。

在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++ 设法在编译时捕获它。

如果我们去看C++标准的草案,我们可以看到一个类直到结束}才完全定义,这是在第9.2节中 类成员第 2 段:

在类说明符的结尾 } 处被视为完全定义的对象类型 (3.9)(或完整类型)。[...]

并且类的所有非静态数据成员都必须是完整的,即第 9 段:

非静态 (9.4) 数据成员不得具有不完整的类型。特别是,C类不应包含 类 C 的非静态成员,但它可以包含指向类 C 对象的指针或引用。

但正如它所说,它可以包含一个指针或引用,这将更接近 Java 的工作方式。