Ответ
Да, и это стандартная практика. Для явного вызова метода базового класса используется оператор разрешения области видимости BaseClass::.
Зачем это нужно?
- Расширение функциональности: Вы можете добавить новое поведение в переопределенном методе, вызвав сначала базовую реализацию.
- Обход виртуального механизма: Даже для виртуальных методов вызов через
Base::будет статическим (не виртуальным) и обратится именно к реализации в базовом классе. - Решение проблемы «сокрытия имени»: Если метод в производном классе перегружает, а не переопределяет метод базового класса, вы все равно можете получить доступ к скрытой базовой версии.
Примеры:
#include <iostream>
class Base {
public:
virtual void log(const std::string& message) {
std::cout << "[Base Log]: " << message << 'n';
}
void utility() { std::cout << "Base utilityn"; }
};
class Derived : public Base {
public:
// 1. Переопределение виртуального метода с вызовом базовой версии.
void log(const std::string& message) override {
// Сначала выполняем базовую логику.
Base::log(message);
// Затем добавляем свою.
std::cout << "[Derived Addendum] Timestamp added.n";
}
// 2. Сокрытие невиртуального метода.
void utility(int x) { // Это НЕ переопределение, а новая перегрузка.
std::cout << "Derived utility with int: " << x << 'n';
}
// Чтобы использовать базовую версию без параметров, можно добавить using или явный вызов.
void callBaseUtility() {
Base::utility(); // Явный вызов метода базового класса.
}
};
int main() {
Derived d;
d.log("Test Message");
// Вывод:
// [Base Log]: Test Message
// [Derived Addendum] Timestamp added.
// d.utility(); // Ошибка компиляции: utility() скрыт.
d.callBaseUtility(); // Вывод: Base utility
// Даже через указатель на базовый класс можно вызвать базовую реализацию?
Base* bPtr = &d;
// bPtr->Base::log("Direct"); // Так нельзя, синтаксис Base:: только внутри класса.
}
Важно: Вызов Base::method работает только из контекста производного класса (в его методах). Извне через указатель на базовый класс так сделать нельзя.