Рассмотрим простой пример (virtual_funct_const.cpp
):
#include <iostream> class A { public: A() { construct(); } ~A() { destruct(); } virtual void construct() { std::cout << "A::construct()" << std::endl; } virtual void destruct() { std::cout << "A::destruct()" << std::endl; } }; class B: public A { public: B() { construct(); } ~B() { destruct(); } virtual void construct() { std::cout << "B::construct()" << std::endl; } virtual void destruct() { std::cout << "B::destruct()" << std::endl; } }; int main() { B b; return 0; }
Что напечатает эта программа?
А вот что:
A::construct()
B::construct()
B::destruct()
A::destruct()
Получается, что конструкторы и деструкторы классов A
и B
при вызове объявленных виртуальными функций construct()
и destruct()
реально вызывали функции только своего класса.
В этом нет никакого секрета, а просто есть правило: виртуальная функция не является виртуальной, если вызывается из конструктора или деструктора.
Правило надо заучивать, что неудобно. Проще понять принцип. А принцип тут в краеугольном камне реализации наследования в C++: при создании объекта конструкторы в иерархии вызываются от базового класса к самому последнему унаследованному. Для деструкторов все наоборот.
Что получается: конструктор класса всегда работает в предположении, что его дочерние классы еще не созданы, поэтому он не имеет права вызывать функции, определенные в них. И для виртуальной функций ему ничего не остается, как только вызвать то, что определено в нем самом. Получается, что механизм виртуальных функций тут как-бы не работает. А он тут действительно не работает, так как таблица виртуальных функций дочернего класса еще не перекрыла текущую таблицу.
В деструкторе все наоборот. Деструктор знает, что во время его вызова все дочерние классы уже разрушены и вызывать у них ничего уже нельзя, поэтому он замещает адрес таблицы виртуальных функций на адрес своей собственной таблицы и благополучно вызывает версию виртуальной функции, определенной в нем самом.
Итак, виртуальная функция не является виртуальной, если вызывается из конструктора или деструктора.