Подтвердить что ты не робот

Почему gcc и clang позволяют мне создавать абстрактный класс?

Следующий код компилируется в широком диапазоне версий gcc и clang - при компиляции и запуске с gcc 5.3.1 он печатает

А()

затем прервет с чистой ошибкой виртуального вызова.

#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: Проводник компилятора

4b9b3361

Ответ 1

Почему gcc и clang позволяют мне создавать абстрактный класс?

Потому что они сломаны, согласно стандарту.

Раздел 10.4 определяет, как работают абстрактные классы. Он содержит эту строку (в С++ 14):

объекты абстрактного класса не могут быть созданы, кроме как субобъекты производного от него класса.

В правилах инициализации ссылок со списками braced-init будет создано временное и привязать его к ссылке. Временами являются объекты. Таким образом, код, который вы написали выше, попытается создать "объект абстрактного класса" как нечто иное, чем "подобъект производного от него класса".

То, что стандарт прямо запрещает. В этом отношении нет никакой двусмысленности в стандарте. В то время как 10.4, p3 указывает места, которые требуется компилятору для неправильной ошибки, если вы вводите их (объявляя абстрактные классы как параметры функции, явные преобразования и т.д.), Стандарт по-прежнему требует, чтобы реализации запрещали построение абстрактного класса как нечто кроме "подобъекта класса, полученного из него".

Временное не является "подобъектом класса, полученного из него". И поэтому компиляторы обязаны запрещать это.

Любой компилятор, который не имеет ошибки.