为什么gcc和clang允许我构造一个抽象类? [英] Why do gcc and clang allow me to construct an abstract class?

查看:102
本文介绍了为什么gcc和clang允许我构造一个抽象类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码在各种gcc和clang版本上编译 - 当编译并运行gcc 5.3.1时,它打印


A()


然后中止纯虚拟调用错误。

  #include< stdio.h> 

class A
{
public:
A(){
printf(A()\\\
);
}
virtual void b()const = 0;
};

int main()
{
const A&一个{};
a.b();
return 0;
}



我实现绑定一个引用的临时不是理想的> think 这种情况被某种类型的生命周期扩展覆盖) - 但是它也可以在尝试调用一个方法时使用一个const引用,如:

  Foo({});为了方便起见,下面是一个使用clang 3.2编译的示例: 

gcc.godbolt.org/#compilers:!((compiler:clang32,options:%27-std%3Dc%2B%2B11%27,source:%27%23include+%3Cstdio.h%3E%0A%0Aclass+A% 0A%7B%0A ++公共:%0A ++ A()+%7B%0A ++++ printf(%22A(%)5Cn%22)%3B%0A ++%7D% b()+ const +%3D + 0%3B%0A%7D%3B%0A%0Aint + main()%0A%7B%0A ++ const + A%26 + a%7B%7D%3B% ab()%3B%0A ++ return + 0%3B%0A%7D%27)),filterAsm:(colouriseAsm:!t,commentOnly:!t,directives: > Compiler Explorer

解决方案


为什么gcc和clang允许我构造一个抽象类?


因为根据标准,它们被破坏了。



10.4节定义了抽象类的工作原理。它包含这一行(在C ++ 14中):


不能创建抽象类的对象,除了类的子对象


带braced-init-lists引用的初始化规则将构造一个临时并将其绑定到引用。临时是对象。因此,上面写的代码将尝试创建一个抽象类的对象,而不是派生自它的类的子对象。



标准明示禁止。在这方面,标准没有歧义。虽然10.4,p3确实指定了编译器需要输出错误的位置(如果你将抽象类声明为函数参数,显式转换等),但标准仍然需要实现来禁止将抽象类构造为东西而不是从其派生的类的子对象。



临时变量不是从其派生的类的子对象。因此,编译器有义务禁止此操作。



任何没有错误的编译器。


The following code compiles on a wide range of gcc and clang versions - when compiled and run with gcc 5.3.1, it prints

A()

then aborts with a pure virtual call error.

#include <stdio.h>

class A
{
public:
    A() {
        printf("A()\n");
    }
    virtual void b() const = 0;
};

int main()
{
    const A& a{};
    a.b();
    return 0;
}

I realise binding a reference to a temporary is not ideal (though I think this case is covered by some sort of lifetime extension) - but it also works when trying to call a method that takes a const reference like:

Foo({});

For convenience here's an example of it compiling with clang 3.2: Compiler Explorer

解决方案

Why do gcc and clang allow me to construct an abstract class?

Because they're broken, according to the standard.

Section 10.4 defines how abstract classes work. It contains this line (in C++14):

no objects of an abstract class can be created except as subobjects of a class derived from it.

The initialization rules for references with braced-init-lists will construct a temporary and bind it to the reference. Temporaries are objects. As such, the code you wrote above will attempt to create an "object of an abstract class" as something other than a "subobject of a class derived from it."

Something the standard expressly forbids. There is no ambiguity in the standard in this regard. While 10.4, p3 does specify places that the compiler is required to out-right error if you type them (declaring abstract classes as function parameters, explicit conversions, etc), the standard still requires implementations to forbid the construction of an abstract class as something other than a "subobject of a class derived from it."

A temporary is not a "subobject of a class derived from it." And therefore, compilers are obligated to forbid this.

Any compiler which does not has a bug.

这篇关于为什么gcc和clang允许我构造一个抽象类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆