在 C++ 中,聚合是(取自语言规范的 8.5.1p1)
an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
因此,#1
不是聚合,但#2
是聚合。为什么 #1
也不是聚合?
struct A { virtual void bark() { } int a; }; // #1
struct B { A b; }; // #2
最佳答案
Why is #1 not an aggregate aswell?
因为聚合的标准定义表明它不是。该定义表明,如果要将类视为聚合类型,则该类不能具有虚函数。而已。这就是“显而易见的船长”答案。
由于您引用了标准定义(并且阅读了它,我想),您已经知道这一点,所以我必须假设您要问的是是否有任何根本原因导致具有虚函数的类不能是聚合类型.
显然,具有虚函数的类必须将其虚表指针(或其他机制)初始化为编译器生成的构造函数的一部分。聚合真正提供的唯一功能(除了用作 POD 等的基本定义之外)是对其数据成员进行大括号初始化的能力。我看不出为什么编译器不能在对虚拟表指针进行初始化时简单地允许花括号初始化语法。
就 B
而言,它可以是一个聚合,因为只要有一种方法可以从提供(或未提供)的任何内容构造数据成员,就可以进行大括号初始化在初始化列表中,即它需要每个数据成员都有一些(编译器生成或不生成)默认、复制或移动构造函数。请记住,聚合的定义是浅的,而不是递归的,如 POD 定义(琐碎的、std-layout),这意味着只有顶级类有这些限制,不是它的子对象。
聚合的定义显然很容易让人联想到 C 的结构限制,而结构的大括号初始化显然也是从 C 继承而来的一个特性。我相信由于历史原因,聚合的定义是这样构建的反射(reflect) C 结构,而不是因为编译器可以做什么或不能做什么。
我肯定会认为没有充分的理由限制聚合没有虚函数。也许应该向标准委员会提出建议以取消此限制(因为它不会破坏任何现有代码)。特别是现在,有了统一的初始化语法,聚合只不过是类,编译器可以在类中生成一个以所有数据成员为参数的构造函数(默认值是默认构造的对象)。聚合的唯一其他目的是集中一些适用于 POD 类的限制(琐碎的、标准布局等),对于这些类,不具有虚函数的限制是合理的(AFAIK),但这只是一个将该限制转移到 POD 的问题。
关于C++ 聚合没有虚函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23248505/