如果我有这样的标题:
#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'
上抱怨。为什么?
答案 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];}