我相信很多人都曾在学习C++的过程中,像下面这样干过:
class Example{Example obj; // error: 不允许使用不完整的类型
};
即在类A中,定义A类型的成员变量。此时编译是无法通过的,我们会得到不允许使用不完整的类型
这样冷冰冰的报错。
这就引出了这篇文章要分享的话题:什么是【不完整类型】?
与函数相同,类类型的定义可以拆分为声明与定义两部分。
class Example; // 声明class Example{ // 声明 + 定义// ...
};
声明的作用是在当前的作用域环境下,使类名可见。定义的作用则是指定该类型所拥有的具体成员。只要一个类型完成了声明,那么编译器就会意识到有这样一个类型存在。但只要该类类型的定义没有完成,这就是一个不完整类型。
不完整类型是指只进行了声明,却没有完成定义的类类型。
在最开始的例子中,由于Example
的定义尚未完全结束,此时Example
属于不完整类型
,这便是报错的原因。
那么为什么C++禁止使用不完整类型呢?
因为,将类型本身用于定义成员变量,是一件很逆天的事情。因为你无法确定在这种层层嵌套下,一个该类型对象的大小究竟是多少!这样程序将无法有效分配内存空间。为此,必须杜绝使用不完整类型来定义变量。
但若将上面的例子改一下,我们将Example
类型的成员换成其指针类型Example*
,编译是可以通过的。
class Example{
private:Example * p_obj; // 编译通过
};
因为指针类型是完整的,无论指向的何种类型,只需确保该种类型的名字在当前作用域下可见即可。 另外,从确定成员所占大小的角度考虑,在C++中,指针的大小是固定的,与指向的具体类型无关。