|
VirtualFunctionInConstructor
Виртуальные функции в конструкторе и деструкторе
Featured Виртуальные функции в конструкторе и деструктореРассмотрим простой пример (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++: при создании объекта конструкторы в иерархии вызываются от базового класса к самому последнему унаследованному. Для деструкторов все наоборот. Что получается: конструктор класса всегда работает в предположении, что его дочерние классы еще не созданы, поэтому он не имеет права вызывать функции, определенные в них. И для виртуальной функций ему ничего не остается, как только вызвать то, что определено в нем самом. Получается, что механизм виртуальных функций тут как-бы не работает. А он тут действительно не работает, так как таблица виртуальных функций дочернего класса еще не перекрыла текущую таблицу. В деструкторе все наоборот. Деструктор знает, что во время его вызова все дочерние классы уже разрушены и вызывать у них ничего уже нельзя, поэтому он замещает адрес таблицы виртуальных функций на адрес своей собственной таблицы и благополучно вызывает версию виртуальной функции, определенной в нем самом. Итак, виртуальная функция не является виртуальной, если вызывается из конструктора или деструктора. |