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

时间:2014-10-29 21:18:48

标签: 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作为类型的情况,我在这里都没有。

1 个答案:

答案 0 :(得分:13)

简答:这是标准中的一个错误,它在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绑定到x;实际上意思是创建一个临时的并绑定对它的引用。来自C ++ 11 [dcl.init.ref] / 3:

  

否则,如果T是引用类型,则T引用的类型的 prvalue temporary 是列表初始化的,并且引用绑定到该临时值。 [注意:像往常一样,如果引用类型是非const类型的左值引用,则绑定将失败并且程序格式错误。 - 后注]

这非常愚蠢,显然此代码的目的是将y直接绑定到x。在C ++ 14中,文本被更改了:

  

否则,如果初始化列表具有E类型的单个元素且T不是引用类型或其引用类型与E引用相关,则从该元素初始化对象或引用;

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


您的错误消息来自编译器遵循C ++ 11的措辞并尝试从base创建临时绑定引用;这会失败,因为base属于抽象类型。