Как вызвать метод базового класса из класса наследника в C++
Что проверяют
Знаете ли вы квалифицированный вызов Base::method() и понимаете ли, как он взаимодействует с виртуальностью и сокрытием имён. Следом обычно спрашивают, что будет, если метод виртуальный, и почему в C++ нет super.
Как отвечать
Основной способ: внутри метода наследника указать имя базового класса и оператор разрешения области видимости.
struct Derived : Base {
void draw() override {
Base::draw();
drawBorder();
}
};Дальше важные детали:
- виртуальность: квалифицированный вызов отключает динамическую диспетчеризацию.
Base::draw()вызовет именно реализациюBase, даже если метод виртуальный. Так расширяют поведение родителя, а не заменяют его; - доступ: из наследника доступны
publicиprotectedметоды базы.privateнедоступен, квалификация этого не обходит; - сокрытие имён: если в наследнике объявлен
draw(int), все перегрузкиdrawиз базы скрываются. Вернуть их можно черезusing Base::draw;в теле класса; - снаружи:
obj.Base::draw()тоже работает и вызывает версию базы для объекта наследника; - нет
super: из-за множественного наследования такого ключевого слова нет. Часто заводят псевдонимusing base = Base;внутри класса, чтобы при смене родителя не править все вызовы. У MSVC есть расширение__super, но оно непереносимо.
При множественном наследовании квалификация обязательна, если имя есть в двух базах: иначе компилятор сообщит о неоднозначности.
Где спотыкаются
Пишут внутри переопределения просто draw() или this->draw(), ожидая версию родителя. Получается вызов самого себя, бесконечная рекурсия и переполнение стека.
Пытаются добраться до базы приведением. static_cast<Base>(*this).draw() создаёт временную копию (срезка), и метод меняет копию, а не объект. static_cast<Base&>(*this).draw() для виртуального метода снова уйдёт в наследника. Работает только Base::draw().
Вызывают виртуальный метод в конструкторе базы и ждут версию наследника. Пока работают конструктор и деструктор Base, объект считается объектом Base, и вызовется его собственная реализация.