Почему это не вызов чистой виртуальной функции?
Я попытался "восстановить" пример в этом ответе, чтобы продемонстрировать, как можно вызывать чистую виртуальную функцию.
#include <iostream>
using namespace std;
class A
{
int id;
public:
A(int i): id(i) {}
int callFoo() { return foo(); }
virtual int foo() = 0;
};
class B: public A
{
public:
B(): A(callFoo()) {}
int foo() { return 3; }
};
int main() {
B b; // <-- this should call a pure virtual function
cout << b.callFoo() << endl;
return 0;
}
Но я не получаю ошибку времени выполнения здесь (с С++ 4.9.2), но вывод 3. Я пробовал то же самое с Borland С++ 5.6.4, но там я получаю нарушение доступа. Я думаю, что foo()
должен быть чистым виртуальным в вызове конструктора базового класса.
Кто не прав? Должен ли я попробовать больше компиляторов? Я прав в своем понимании виртуальных функций?
Ответы
Ответ 1
В вашем коде Undefined Поведение: UB вызывает функцию-член на объекте (даже не виртуальном), прежде чем все базовые классы будут инициализированы. С++ 14 (n4140) 12.6.2/14, акцент мой:
Функции-члены (включая функции виртуальных членов, 10.3) могут быть вызваны для строящегося объекта. Аналогично, строящийся объект может быть операндом оператора typeid
(5.2.8) или dynamic_cast
(5.2.7). Однако, если эти операции выполняются в ctor-инициализаторе (или в функции, называемой непосредственно или косвенно из ctor-инициализатора) до того, как все mem-инициализаторы для базовых классов завершились, результат операции undefined....
ctor-initializer - это весь список, следующий за :
. mem-initializer является одним из элементов этого списка.
Ответ 2
Оператор B b;
вызывает конструктор по умолчанию B
.
При построении B
ничего не относящееся к B
построено до тех пор, пока A
не будет полностью построено.
Поэтому при попытке вызвать callFoo()
поведение undefined, так как вы не можете полагаться на настройку v-таблицы для класса B
.
Вкратце: поведение вызова чистой виртуальной функции при построении абстрактного класса undefined.