Можно ли вызвать метод базового класса из производного класса?

«Можно ли вызвать метод базового класса из производного класса?» — вопрос из категории ООП, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, и это стандартная практика. Для явного вызова метода базового класса используется оператор разрешения области видимости BaseClass::.

Зачем это нужно?

  1. Расширение функциональности: Вы можете добавить новое поведение в переопределенном методе, вызвав сначала базовую реализацию.
  2. Обход виртуального механизма: Даже для виртуальных методов вызов через Base:: будет статическим (не виртуальным) и обратится именно к реализации в базовом классе.
  3. Решение проблемы «сокрытия имени»: Если метод в производном классе перегружает, а не переопределяет метод базового класса, вы все равно можете получить доступ к скрытой базовой версии.

Примеры:

#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 работает только из контекста производного класса (в его методах). Извне через указатель на базовый класс так сделать нельзя.