在 C++ 中,聚合是(取自语言规范的 8.5.1p1)
一个数组或一个类(第 9 条),没有用户提供的构造函数(12.1),没有私有或
受保护的非静态数据成员(第 11 条),无基类(第 10 条),并且无虚函数(10.3)。
So, #1
不是一个聚合,但是#2
是一个聚合体。为什么是#1
也不是一个聚合体?
struct A { virtual void bark() { } int a; }; // #1
struct B { A b; }; // #2
为什么#1 也不是聚合?
因为聚合的标准定义表明事实并非如此。该定义表明,如果类被视为聚合类型,则该类不能具有虚函数。就是这样。这就是“显而易见的队长”的答案。
既然您引用了标准定义(并且阅读了它,我猜),您已经知道这一点,所以我必须假设您要问的是是否存在任何根本原因为什么具有虚函数的类不能成为聚合类型。
显然,具有虚函数的类必须将其虚表指针(或其他机制)初始化为编译器生成的构造函数的一部分。聚合真正提供的唯一功能(除了充当 POD 等的基本定义之外)是对其数据成员进行大括号初始化的能力。我看不出编译器在初始化虚拟表指针时不能简单地允许大括号初始化语法的任何原因。
据,直到...为止B
就而言,它可以是一个聚合,因为只要有一种方法可以从初始化列表中提供(或未提供)的任何内容构造数据成员,即它需要每个数据成员具有一些(编译器生成的或不是编译器生成的)默认、复制或移动构造函数。请记住,聚合的定义是shallow相对于递归的就像 POD 定义(简单,std-layout)一样,这意味着只有顶级类有这些限制,而其子对象则没有。
聚合的定义显然很容易让人想起 C 结构体的限制,而结构体的大括号初始化显然也是从 C 继承下来的一个特性。我相信,由于历史原因,聚合体的定义是这样构建的,它反映了 C 结构体,而不是因为编译器可以做什么或不能做什么。
我当然认为没有充分的理由限制聚合不具有虚拟函数。也许应该向标准委员会提出建议以取消此限制(因为它不会破坏任何现有代码)。特别是现在,使用统一的初始化语法,聚合只不过是类,编译器可以在其中生成一个以所有数据成员作为参数的构造函数(默认值是默认构造的对象)。聚合的唯一其他目的是集中一些适用于 POD 类的限制(琐碎的、标准布局等),对于这些类,不具有虚拟函数的限制是合理的(AFAIK),但这只是一个将该限制转移到 POD 的问题。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)