13

拥有一个聚合公共基类(甚至是多个聚合公共基类)会使一个类失去聚合类的优良属性是什么意思?

“聚合基类”的定义来自 http://en.cppreference.com/w/cpp/language/aggregate_initialization http://en.wikipedia.org/wiki/C++_classes#Aggregate_classes


聚合类的优点:

  • 在不定义构造函数的情况下,可以通过传入用大括号括起来的值列表来初始化聚合类型,以初始化其成员(或基类,如果它们允许的话)。
  • 聚合类型被认为是“简单的”(POD的泛化),并且可以用作constexprs的文字类型。

来自http://en.cppreference.com/w/cpp/language/aggregate_initialization#Example的简化示例:

#include <string>
#include <array>
struct S {
  int x;
  struct Foo {
    int i;
    int j;
    int a[3];
  } b;
};

int main()
{
  S s1 = { 1, { 2, 3, {4, 5, 6} } };
  S s2 = { 1, 2, 3, 4, 5, 6}; // same, but with brace elision
}

另请参阅: 什么是聚合和 POD,它们如何/为什么特别?

4

4 回答 4

4

根据http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3308.pdf

尽管标准有明确的意图,但类型 B 不是文字类型:

struct A {}; struct B : A {};

这是因为在使用 odr 之前,它的构造函数没有被隐式定义,并且在那之前它没有 constexpr 构造函数。

不过,老实说,我不确定这意味着什么。

于 2013-11-08T23:43:50.483 回答
3

这是来自 c++11 标准的聚合的定义,这就是我能给出的所有内容,而不必试图猜测委员会在做出这个决定时的想法。

1 聚合是一个数组或一个类(第 9 条),没有用户提供的构造函数 (12.1),没有用于非静态数据成员 (9.2) 的大括号或等号初始化器,没有私有或受保护的非静态数据成员(第 11 条),没有基类(第 10 条),也没有虚函数(10.3)。

粗体字表示聚合没有基类。

至于另一个答案提出的继承问题,您可以使用继承进行统一初始化。注意:A 仍然是一个聚合。

struct A {                                                                         
    int val_A;                                                                                                                        
};                                                                                 

struct B : public A {                                                              
    int val_B;                                                                     
    B(int a, int b) : A{a}, val_B(b) {}                                            
};                                                                                 
int main() {                                                                       
    B b {2,3};                                                                     
    return 0;                                                                      
}  

您只需给 B 一个构造函数,IMO 标准可以很容易地选择它作为默认值。聚合可能被保留,因为它们在以前的标准中,但事实是使用 c++11 特性,你甚至不需要它们。事实上,一个问题是std::array需要双括号,因为它没有初始化列表构造函数,我认为这个问题在 c++14 中得到了解决。

我想补充一点,考虑到统一初始化和初始化列表的新特性,我看不到聚合给类增加了多少。

于 2013-11-07T21:16:53.267 回答
3

由于具有公共、非虚拟基类的 C++17 类可以是聚合。

struct Base1 {
 int a, b;
};
struct Base2 {
 int c;
};

struct Foo : Base1, Base2 {
    int d, e;
};

struct Foo 的对象可以聚合初始化。以下初始化是等效的:

Foo foo {Base1{1, 2}, Base2{3}, 4, 5};
Foo foo {{1, 2}, {3}, 4, 5};
Foo foo {1, 2, 3, 4, 5};
于 2021-07-23T14:45:54.653 回答
2

你将如何初始化基类?

Derived d = {{1, 2}, 3, 4};

或者

Derived d = {1, 2, 3, 4};

Derived d = {3, 4};

允许吗?

为了避免这一切,没有基类。

于 2013-11-07T21:18:12.930 回答