Наследование классов

Этот урок сложнее предыдущих. Наследование нужно не для экономии нескольких строк, а для описания отношения «один тип является разновидностью другого типа».
Базовый класс описывает общую часть. Производный класс получает эту общую часть и добавляет своё поведение. При public-наследовании производный объект можно использовать как объект базового типа.
Простая идея
Если разные устройства можно обслуживать одной командой update, можно задать общий базовый класс.
#include <iostream>
using namespace std;
class Module {
public:
void reset() {
cout << "reset" << endl;
}
};
class Sensor : public Module {
public:
void read() {
cout << "read" << endl;
}
};
int main() {
Sensor s;
s.reset();
s.read();
return 0;
}
Sensor является разновидностью Module, поэтому объект s получил метод reset.
public-наследование
class Sensor : public Module {
};
Эта запись означает: Sensor открыто наследует Module. Проверочная фраза: «датчик является модулем». Если фраза звучит странно, наследование не подходит.
| Связь | Что выбрать |
|---|---|
| датчик является модулем | наследование возможно |
| робот содержит мотор | поле класса |
| мотор содержит мощность | поле класса |
| отчёт содержит числа | массив или вектор |
virtual и override
Иногда общий метод должен работать по-разному в разных производных классах.
#include <iostream>
using namespace std;
class Module {
public:
virtual void update() {
cout << "module" << endl;
}
};
class Sensor : public Module {
public:
void update() override {
cout << "sensor" << endl;
}
};
class Motor : public Module {
public:
void update() override {
cout << "motor" << endl;
}
};
void service(Module* m) {
m->update();
}
int main() {
Sensor s;
Motor m;
service(&s);
service(&m);
return 0;
}
Вывод:
sensor
motor
virtual разрешает выбрать метод по настоящему типу объекта. override просит компилятор проверить, что производный класс действительно заменяет метод базы.

Виртуальный деструктор
Если базовый класс используют через указатели, обычно добавляют виртуальный деструктор:
class Module {
public:
virtual ~Module() {
}
virtual void update() {
}
};
Это нужно для безопасного удаления производного объекта через указатель на базовый класс. В этом уроке мы не создаём такие объекты через new, но правило важно запомнить для будущих проектов.
Когда не нужно наследование
Плохая модель:
class Robot : public Motor {
};
Робот не является мотором. Робот содержит мотор. Лучше так:
class Robot {
private:
Motor left;
Motor right;
};
Если связь описывается словом «содержит», используйте поле, а не наследование.
Практика
- Создайте базовый класс
Moduleс методомreset. - Создайте производный класс
Sensor. - Проверьте, что объект
Sensorможет вызватьreset. - Добавьте виртуальный метод
update. - Создайте два производных класса с разным
update. - Для пар «робот — мотор» и «датчик — модуль» выберите наследование или поле.
Проверьте себя
- Что такое базовый класс?
- Что такое производный класс?
- Как читается
class Sensor : public Module? - Что делает
virtual? - Зачем нужен
override? - Почему робот обычно содержит мотор, а не наследуется от него?
Сначала ответьте без подсказки. Ответ можно считать полным, если вы:
- формулируете основную мысль своими словами;
- называете важные условия, ограничения или меры безопасности;
- для схемы, кода или расчёта показываете ход решения и ожидаемый результат.
Если один из пунктов объяснить не получается, найдите соответствующую главу статьи, перечитайте её и повторите ответ.
Словарь статьи
| Термин | Значение |
|---|---|
| наследование | создание класса на основе другого класса |
| базовый класс | общий класс |
| производный класс | класс-наследник |
public-наследование | открытая связь «является» |
virtual | выбор метода по настоящему типу объекта |
override | проверка переопределения метода |
| композиция | объект содержит другие объекты как поля |
Связанные темы
- Классы — поля, методы и объекты.
- Продолжаем изучать классы — интерфейс и реализация.
- Указатели — передача объекта через адрес.
Источники
- C++ Working Draft. Derived classes: https://eel.is/c++draft/class.derived
- Microsoft Learn. Inheritance: https://learn.microsoft.com/en-us/cpp/cpp/inheritance-cpp
- C++ Core Guidelines. Virtual functions: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c128-virtual-functions-should-specify-exactly-one-of-virtual-override-or-final