c++ - 当 parent 初始化时,为什么构造函数初始化列表中的 C++11 花括号初始化不起作用?

标签 c++ c++11 reference initialization list-initialization

在初始化对抽象类型的引用时,构造函数初始化列表中的 {} 初始化与 () 初始化有何不同?拿下面的类吧:

class AbstractBase
{
public:
    AbstractBase() {}
    virtual ~AbstractBase() = default;

    virtual void ab() = 0;
};

class Foo : public AbstractBase
{
public:
    Foo() {}

    void ab() {}
};

class Bar
{
public:
    Bar(const AbstractBase& base) : myBase{base} {}

private:
    const AbstractBase& myBase;
};


int main()
{
    Foo f{};
    Bar b{f};

}

编译的时候报错

test5.cpp: In constructor ‘Bar::Bar(const AbstractBase&)’:
test5.cpp:22:48: error: cannot allocate an object of abstract type ‘AbstractBase’
     Bar(const AbstractBase& base) : myBase{base}
                                                ^
test5.cpp:2:7: note:   because the following virtual functions are pure within ‘AbstractBase’:
 class AbstractBase
       ^
test5.cpp:8:18: note:   virtual void AbstractBase::ab()
     virtual void ab() = 0;

换行

Bar(const AbstractBase& base) : myBase(base) {}

它编译并运行良好。

阅读 Stroustrup 的 C++11 书,我的印象是 {} 在大多数情况下都与 () 相同,除非在采用 std::initializer_list<> 的构造函数和其他构造函数之间存在歧义,以及使用 auto 作为类型的情况,我在这里都没有这样做。

最佳答案

简短回答:这是标准中的一个错误,已在 C++14 中修复,g++ 4.9 已修复(也可追溯应用于 C++11 模式)。 Defect Report 1288


这是一个更简单的例子:

struct S
{
    int x;
    S() { }     // this causes S to not be an aggregate (otherwise aggregate 
                // initialization is used instead of list initialization)
};

S x = 5;
S const &y { x } ;    

x = 6;
std::cout << y << std::endl;     // output : 5

在C++11的文本中,S const &y {x};的意思是不把y绑定(bind)到x ;实际上意思是创建一个临时的并绑定(bind)一个引用。来自 C++11 [dcl.init.ref]/3:

Otherwise, if T is a reference type, a prvalue temporary of the type referenced by T is list-initialized, and the reference is bound to that temporary. [Note: As usual, the binding will fail and the program is ill-formed if the reference type is an lvalue reference to a non-const type. —end note ]

这很傻,很明显这段代码的目的是将y直接绑定(bind)到x。在 C++14 中,文本已更改:

Otherwise, if the initializer list has a single element of type E and either T is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element;

由于类型与自身(或其基类之一)相关,因此在我的示例和您的实际代码中,它实际上应该正确绑定(bind)。


您的错误消息来自编译器,遵循 C++11 的措辞,并试图从 base 创建一个临时文件以将引用绑定(bind)到;这失败了,因为 base 是抽象类型。

关于c++ - 当 parent 初始化时,为什么构造函数初始化列表中的 C++11 花括号初始化不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26640866/

相关文章:

c++ - 封装在头文件中

c++ - 带有可移动、不可复制参数的 std::thread

c++ - 递归 unordered_map

Silverlight 4 程序集共享问题

python - 引用python中的列表容器理解for循环

java - 为什么原始类型引用可以引用泛型实例?

c++ - 为什么 GNU make 总是重新链接我的项目?

c++ - C++ 中的字符串对象末尾是否有空字符?

c++ - 什么时候应该在模板函数中使用 typename?

c++ - 如何在作为 map 键的 vector 的 2 个数组中搜索公共(public)元素?