2016-05-04 5 views
23

Следующий код компилирует на широком диапазоне НКУ и лязг версий - при компиляции и запуска с GCC 5.3.1, он печатаетПочему gcc и clang позволяют мне создавать абстрактный класс?

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; 
} 

Я понимаю, что связывание ссылки на временном не является идеальным (хотя я думаю этот случай покрываются каким-то продление срока эксплуатации) - но он также работает при попытке вызвать метод, который принимает константный ссылка как:

Foo({}); 

Для удобства здесь приведен пример его составления с лязгом 3.2: Compiler Explorer

+1

Построение абстрактного класса с помощью указателя или ссылки разрешено, помните? – DeiDei

+2

@DeiDei Я этого не помню, но это объясняло бы почему. РЕДАКТИРОВАТЬ: Чтобы быть ясным, на самом деле он создает объект, а не только ссылку. – Matt

+0

«вид продления жизни» - жизнь заканчивается на завершающей стадии - так что на ';' - но поскольку ничего больше не происходит, вы просто продолжаете с неопределенным поведением. – Soren

ответ

16

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

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

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

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

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

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

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

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

+1

Похоже на меня, этот раздел, похоже, не имеет никакого отношения к нему. Теперь я проверил MSVC 2015, который также просто печатает ошибку: «A»: не может создать экземпляр абстрактного класса », поэтому, по крайней мере, это не _all_ компиляторы – Matt

+2

@Matt: тогда вы должны сообщить об ошибке« gcc' и 'clang». Поздравления !!! – Destructor

+0

Вы забыли упомянуть в своем ответе, что код OP вызывает неопределенное поведение IMHO. См. Http://melpon.org/wandbox/permlink/b8w0T43wNxvzeTME. – Destructor