← Назад к вопросам

Что такое ООП?

1.0 Junior🔥 301 комментариев
#ООП и проектирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ключевое слово override в C++

Override — одно из самых важных ключевых слов в современном C++11+, которое спасает от множества ошибок при переопределении виртуальных функций.

Проблема до override

class Base {
public:
    virtual void process(int x);
    virtual void calculate();
};

class Derived : public Base {
public:
    // ОШИБКА 1: Опечатка в имени функции
    void proccess(int x); // Не переопределяет Base::process!
    
    // ОШИБКА 2: Неправильная сигнатура
    void calculate(double x); // Не переопределяет, создаёт новую!
    
    // ОШИБКА 3: Забыл const
    void process(int x) const; // Не переопределяет!
};

// Программист думает, что переопределил, но нет!
Base* ptr = new Derived();
ptr->process(5); // Вызовет Base::process, не Derived::process!

Решение: override

class Derived : public Base {
public:
    void process(int x) override; // OK
    void calculate() override; // OK
    
    void proccess(int x) override; // ОШИБКА КОМПИЛЯТОРА!
    void calculate(double x) override; // ОШИБКА КОМПИЛЯТОРА!
    void process(int x) const override; // ОШИБКА КОМПИЛЯТОРА!
};

Компилятор проверит:

  • Что функция в базовом классе существует и виртуальна
  • Что сигнатура совпадает (имя, параметры, const/volatile)
  • Что совпадает тип возврата (или ковариантен)

Правила для override

Совпадают ли сигнатуры?

class Base {
    virtual void func(int x);
};

class Derived : public Base {
    // OK - совпадает всё
    void func(int x) override;
    
    // ОШИБКА - разные параметры
    void func(double x) override;
    
    // ОШИБКА - теряется const
    void func(int x) const override;
    
    // ОШИБКА - теряется volatile
    void func(int x) volatile override;
};

Ковариантные типы возврата - OK:

class Shape { virtual ~Shape() = default; };
class Circle : public Shape {};

class ShapeFactory {
    virtual Shape* create() { return new Shape(); }
};

class CircleFactory : public ShapeFactory {
    // OK - Circle* - это Circle (подтип Shape)
    Circle* create() override { return new Circle(); }
};

final - запрещаем дальнейшее переопределение

class Base {
    virtual void func();
};

class Derived : public Base {
    void func() override final; // Никто больше не может переопределить!
};

class DerivedAgain : public Derived {
    void func() override; // ОШИБКА КОМПИЛЯТОРА!
};

// Также можно запретить наследование от класса
class Final final { // final применен к классу
};

class BadDerived : public Final { }; // ОШИБКА!

Pure virtual с override

class Interface {
    virtual void process() = 0;
};

class AbstractImpl : public Interface {
    // Оставляем чистой виртуальной
    void process() override = 0;
};

class ConcreteImpl : public AbstractImpl {
    // Реализуем
    void process() override { std::cout << "done"; }
};

Лучшие практики

Правило 1: Всегда используй override

// ПЛОХО - без override можно случайно создать новую функцию
class Derived : public Base {
    void func(); // Переопределение или новая функция?
};

// ХОРОШО - явно указываем намерение
class Derived : public Base {
    void func() override; // Явно переопределяем
};

Правило 2: Используй virtual только в базовом классе

// Неправильно - verbose и запутано
class Base {
    virtual void func();
};

class Derived : public Base {
    virtual void func() override; // virtual - лишний!
};

// Правильно - virtual нужен только в Base
class Base {
    virtual void func();
};

class Derived : public Base {
    void func() override; // Явное - лучше, чем неявное
};

Правило 3: Кодстайл - размещай override в конце

// ХОРОШО
void some_long_function_name(
    const std::string& param1,
    const std::vector<int>& param2
) override;

// ПЛОХО
void some_long_function_name(
    const std::string& param1,
    const std::vector<int>& param2
) override final const;

Типичные ошибки

Ошибка: забыл const

class Base {
    virtual void read() const;
};

class Derived : public Base {
    void read() override; // ОШИБКА - забыл const!
};

Ошибка: неправильный return type

class Base {
    virtual int* allocate();
};

class Derived : public Base {
    // ОШИБКА - const int* не совпадает с int*
    const int* allocate() override;
};

Ошибка: виртуальность в 64-битном vs 32-битном

// Редкий случай, но возможен:
class Base {
    virtual void process(size_t x); // size_t зависит от платформы
};

class Derived : public Base {
    void process(unsigned long x) override; // Может не совпадать!
};

Заключение

Override - это не просто синтаксис, это страховка:

  • Ловит опечатки на этапе компиляции
  • Документирует намерение переопределить
  • Предотвращает subtle bugs в production
  • Обязателен в современном C++ (C++11+)

Всегда используй override, это стоит нескольких дополнительных символов!

Что такое ООП? | PrepBro