为什么没有带有支撑初始化列表的构造函数/虚拟析构函数可以工作?

时间:2017-11-30 15:42:30

标签: c++ constructor virtual-destructor

为什么下面的代码没有编译?

#include <vector>

class Foo
{
public:
    Foo()
    { }

    virtual ~Foo()
    { }

    std::vector<int> aVec;
};


Foo bar =
{
    { 1, 2, 3, 4, 5 }
};

以下代码编译:

#include <vector>

class Foo
{
public:

    /*Foo()
    { }

    virtual*/ ~Foo()
    { }

    std::vector<int> aVec;
};


Foo bar =
{
    { 1, 2, 3, 4, 5 }
};

除了参考语言规则外,请详细说明这些规则背后的基本原理。

为什么构造函数和虚析构函数的存在会停止初始化?

3 个答案:

答案 0 :(得分:5)

因为Foo属于类类型,所以支撑的初始化列表被视为aggregate initialization。除其他外,这需要该类没有显式构造函数或虚拟成员:

  

聚合初始化是列表初始化的一种形式,其中   初始化聚合。聚合是以下类型之一:

     

类类型(通常是struct或union),它有......

     
      
  • 没有私人或受保护的非静态数据成员

  •   
  • 没有用户提供,继承或显式(自C ++ 17)构造函数(允许显式默认或删除构造函数)

  •   
  • 没有虚拟,私有或受保护的基类
  •   
  • 没有虚拟成员函数
  •   
  • 默认成员初始值设定项
  •   

答案 1 :(得分:5)

您正在使用的列表初始化形式称为link。它用于聚合类型。类型作为聚合的要求之一是它没有用户提供的构造函数。

通过提供构造函数,编译器将尝试将列表初始化与定义的构造函数之一进行匹配。它更喜欢构造函数采用单aggregate initialization。由于您没有提供一个,它将尝试查找与您的初始化列表提供的参数匹配的构造函数。由于唯一的构造函数是不带参数的默认构造函数,因此找不到匹配项。

答案 2 :(得分:1)

Foo bar = { { 1, 2, 3, 4, 5 } };aggregate initialization。它仅为数组和“聚合”类类型定义。添加任何构造函数或虚拟成员意味着该类型不是聚合的。