为什么 gcc 和 clang 允许我构造一个抽象 class?
Why do gcc and clang allow me to construct an abstract class?
以下代码可在各种 gcc 和 clang 版本上编译 - 当使用 gcc 5.3.1 编译并 运行 时,它会打印
A()
然后因纯虚拟调用错误而中止。
#include <stdio.h>
class A
{
public:
A() {
printf("A()\n");
}
virtual void b() const = 0;
};
int main()
{
const A& a{};
a.b();
return 0;
}
我意识到将引用绑定到临时对象并不理想(虽然我 认为 这种情况包含在某种生命周期延长中) - 但它在尝试调用时也有效一个采用 const 引用的方法,例如:
Foo({});
为方便起见,这里有一个用 clang 3.2 编译的例子:Compiler Explorer
Why do gcc and clang allow me to construct an abstract class?
因为按照标准,它们坏了。
10.4 节定义了抽象 classes 是如何工作的。它包含这一行(在 C++14 中):
no objects of an abstract class can be created except as subobjects of a class derived from it.
带有花括号初始化列表的引用的初始化规则将构造一个临时对象并将其绑定到引用。临时对象是对象。因此,您在上面编写的代码将尝试创建一个 "object of an abstract class" 作为 "subobject of a class derived from it."
以外的东西
标准明确禁止的内容。标准在这方面没有歧义。虽然 10.4,p3 确实指定了编译器需要在您键入它们时彻底消除错误的地方(将抽象 classes 声明为函数参数、显式转换等),该标准仍然要求实现禁止构造抽象 class 作为 "subobject of a class derived from it."
以外的东西
临时文件不是 "subobject of a class derived from it." 因此,编译器有义务禁止这样做。
任何没有错误的编译器。
以下代码可在各种 gcc 和 clang 版本上编译 - 当使用 gcc 5.3.1 编译并 运行 时,它会打印
A()
然后因纯虚拟调用错误而中止。
#include <stdio.h>
class A
{
public:
A() {
printf("A()\n");
}
virtual void b() const = 0;
};
int main()
{
const A& a{};
a.b();
return 0;
}
我意识到将引用绑定到临时对象并不理想(虽然我 认为 这种情况包含在某种生命周期延长中) - 但它在尝试调用时也有效一个采用 const 引用的方法,例如:
Foo({});
为方便起见,这里有一个用 clang 3.2 编译的例子:Compiler Explorer
Why do gcc and clang allow me to construct an abstract class?
因为按照标准,它们坏了。
10.4 节定义了抽象 classes 是如何工作的。它包含这一行(在 C++14 中):
no objects of an abstract class can be created except as subobjects of a class derived from it.
带有花括号初始化列表的引用的初始化规则将构造一个临时对象并将其绑定到引用。临时对象是对象。因此,您在上面编写的代码将尝试创建一个 "object of an abstract class" 作为 "subobject of a class derived from it."
以外的东西标准明确禁止的内容。标准在这方面没有歧义。虽然 10.4,p3 确实指定了编译器需要在您键入它们时彻底消除错误的地方(将抽象 classes 声明为函数参数、显式转换等),该标准仍然要求实现禁止构造抽象 class 作为 "subobject of a class derived from it."
以外的东西临时文件不是 "subobject of a class derived from it." 因此,编译器有义务禁止这样做。
任何没有错误的编译器。