初始化对抽象类型的引用时,构造函数初始化列表中的{}初始化与()初始化的不同之处是什么?以下课程栏:
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作为类型的情况,我在这里都没有。
答案 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
属于抽象类型。