为什么编译器在使用引用时需要完整类型?

时间:2013-11-25 15:07:49

标签: c++ class

如果我有这样的标题:

#include <vector>

class Data;
class A {
  // const Data& getData( int i ) const { return a[i]; }
  std::vector<Data> a;
};

编译器正常编译它,因为它不需要知道有关数据类型的信息。

通过引用重新调整值不依赖于类实现,因此不需要任何类内部知识。 但当我取消注释时,访问者编译器开始在invalid use of incomplete type 'class Data'上抱怨。为什么?

4 个答案:

答案 0 :(得分:4)

因此,C ++标准在这一点上并不是特别清楚。您遇到的问题是,当vector<Data>不是完整类型时,您是否可以实例化Data

如果我们看看第17.6.4.8节第2段,我们会发现以下声明:

  

特别是,在以下情况下效果未定义:

     
      
  • ...
  •   
  • 如果在实例化模板组件时将不完整类型(3.9)用作模板参数,除非特别允许该组件。
  •   

std::vector没有明确允许模板参数的不完整类型,因此这在技术上是无效的代码。


这意味着这是无效代码,即使您的编译器接受它。

class Data;
class A {
    std::vector<Data> a;
};

答案 1 :(得分:3)

感谢人们的反应,我更好地理解了这个问题。 当我们摆脱std::vector

时,它变得更加清晰
class Data;
class A {
  const Data& getData( int i ) const { return a[i]; }
  Data* a;
};

返回i - 数组a的元素,需要知道它在内存中的位置。为此,需要知道sizeof(Data),这对于不完整类型是不可能的。

std :: vector应该有完全相同的问题。

答案 2 :(得分:1)

因为知道存在类Data不足以知道std::vector<Data>::operator[](size_t i)应该做什么,甚至知道它是否存在。这是类模板本质的基础。

答案 3 :(得分:1)

声明中不需要完整的类型。它需要一个完整的类型才能调用向量构造函数和析构函数(或任何其他成员)。这是在需要定义结构或类的大小时。

在您的代码中,A的构造函数和析构函数被声明为默认值,因此在头文件中定义。向量不能分配或释放它不知道的大小的东西,所以它是barfs。您可以通过在“A.h”中明确声明析构函数和构造函数来解决此问题,并确保在定义任何成员函数之前定义Data。

以下代码有效且有效。

//"A.h"
class Data; // forward declaration only
class A
{
public:
  A();
  ~A();
  const Data& getData( int i ) const;
  std::vector<Data> a;
};

//"A.cpp"
#include "A.h"
class Data {int i;}; // actual class here before the definition of A::A(),...

A::A(){}
A::~A(){}
Data& A::getData(int i) const {return a[i];}