Программа напечатает пять строк: Base, Derived, Derived, Derived, Base. Во время конструкции и разрушения виртуальный вызов ограничен текущим конструируемым или разрушаемым классом.
Как виртуальные функции и деструкторы влияют на порядок вывода при удалении через указатель базового класса
Программа напечатает пять строк: Base, Derived, Derived, Derived, Base. Во время конструкции и разрушения виртуальный вызов ограничен текущим конструируемым или разрушаемым классом.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Вопрос: какой набор строк будет выведен программой, учитывая особенности работы виртуальных функций, последовательность вызовов конструкторов и деструкторов, а также поведение при удалении объекта через указатель базового типа.
# include <iostream>
struct Base {
Base() { print(); }
virtual void print() { std::cout << "Base" << std::endl; }
virtual ~Base() { print(); }
};
struct Derived : Base {
Derived() { print(); }
virtual void print() { std::cout << "Derived" << std::endl; }
virtual ~Derived() { print(); }
};
int main(int argc, char** argv) {
Base* ptr = new Derived();
ptr->print();
delete ptr;
}
Разберите, как происходит вызов print в конструкторе базового класса, как переопределяется метод в производном классе, и какие функции будут выполнены при разрушении объекта, когда удаление происходит через указатель базового типа.
Ответ
Программа напечатает пять строк: Base, Derived, Derived, Derived, Base. Во время конструкции и разрушения виртуальный вызов ограничен текущим конструируемым или разрушаемым классом.
Первую строку печатает конструктор Base, вторую — конструктор Derived. После создания объекта ptr->print() вызывает Derived::print, хотя ptr имеет тип Base*.
Виртуальный деструктор обеспечивает разрушение Derived перед Base. В теле ~Derived вызывается Derived::print, а в ~Base — Base::print. Если бы базовый деструктор не был виртуальным, удаление этого Derived через Base* не имело бы корректного определённого поведения.
Источник: eel.is.