Наследование - повторное использование и иерархия типов
Разработчику
Аналитику
Тестировщику
Архитектору
Инженеру
Наследование
Что такое наследование?
★ Наследование (в терминах ООП — генерализация в иерархии) — отношение "родитель / потомок", при котором дочерний класс заимствует структуру и контракт родителя и может расширять или уточнять их. Снижает дублирование — общее выносят в базовый (супер-, родительский) класс, отличия оставляют в производных (под-, дочерних) классах.
| Термин | Синонимы |
|---|---|
| Базовый класс | суперкласс, родитель, предок |
| Производный класс | подкласс, наследник, потомок |
| Отношение | extends / : / НАСЛЕДУЕТ |
При порождении класса производный тип наследует поля и методы базового и может обращаться к общим (public) и защищённым (protected) членам так, будто они объявлены в самом производном классе. К частным (private) данным базового класса снаружи его методов доступа нет — только через публичный интерфейс базы.
В C++ и Java конструктор производного класса обязан инициализировать базовую часть объекта: сначала вызывается конструктор предка (явно Base(args) или неявно по умолчанию), затем выполняется тело конструктора наследника. Если в базе и в потомке есть члены с одинаковым именем, внутри методов потомка по умолчанию видна версия потомка; к версии базы обращаются через квалификатор (Base::member в C++, super в Java). Подробнее — ООП в C++, конструкторы.
К примеру, у нескольких классов совпадают поля модель и год — их выносят в Транспорт, а Автомобиль и Велосипед добавляют своё поведение.
Иерархия классов поддерживает повторное использование кода и единообразную типизацию: переменная типа Транспорт может ссылаться на любой наследник, если дальше нужен полиморфизм подтипов.

Play ITЗагрузка интерактивного демо…
Базовый класс
★ Базовый класс (суперкласс) — это класс, который предоставляет свои свойства или методы для наследования. Он описывает общие характеристики и поведение, которые могут быть полезны для подклассов.
КЛАСС Транспорт
поля: модель, год
метод Запустить()
вывести("Транспорт запущен")
конец
КОНЕЦ
КЛАСС Автомобиль НАСЛЕДУЕТ Транспорт
поле количество_колёс
метод Запустить()
вывести("Автомобиль поехал")
конец
КОНЕЦ
Пример (тот же смысл на псевдокоде, близком к Java):
Код ITЗагрузка примера кода…
Здесь класс Транспорт является базовым классом. Он содержит общие атрибуты (модель, год) и метод (запустить()).
Подкласс
Производный класс (или подкласс) — это класс, который наследует свойства и методы базового класса. Подкласс может использовать унаследованные элементы "как есть", добавлять новые элементы или переопределять унаследованные методы.
Пример:
Код ITЗагрузка примера кода…
Здесь класс Автомобиль наследует модель, год и метод запустить() от класса Транспорт. Также он добавляет поле количество_колёс и метод ехать(), и кроме этого - переопределяет метод запустить().
Интерфейс
★ Интерфейс — это набор методов, которые должны быть реализованы в классах, использующих этот интерфейс, и интерфейсы не содержат реализации методов. Они используются для определения "контракта", которому должны следовать классы.
Пример:
Код ITЗагрузка примера кода…
Здесь класс Автомобиль реализует интерфейс Запускаемый и обязан реализовать метод запустить().
Сравнение абстрактного класса и интерфейса с таблицей и примером умного дома — в Абстракции. Ниже — как это выглядит в контексте наследования.
Абстрактный класс
- содержит и готовые методы, и методы без реализации (их допишут наследники);
- может хранить поля и вызывать конструктор при создании объекта;
- экземпляр самого абстрактного класса создать нельзя — только наследника;
- у класса может быть один такой родитель.
Пример:
Код ITЗагрузка примера кода…
Здесь класс Автомобиль наследует абстрактный класс Транспорт и обязан реализовать метод ехать().
Множественное наследование
★ Множественное наследование — это возможность наследовать свойства и методы сразу нескольких классов. Это мощный механизм, но он может вызывать проблемы, такие как "конфликт имён" (если два родительских класса имеют методы с одинаковыми именами).
Пример:
Код ITЗагрузка примера кода…
Здесь класс Автомобиль наследует методы от классов Двигатель и Колёса.
Важно — не все языки программирования поддерживают множественное наследование (например, Java не поддерживает, но позволяет использовать интерфейсы для достижения похожего эффекта).
Представим, что класс D наследуется от B и С. Оба класса B и C наследуются от общего предка - класса A. Если в классе A есть какой-то метод или поле, то возникает неоднозначность — когда мы обращаемся к этому методу или полю через объект D, какой именно экземпляр использовать — от B или от C? Компилятор не знает, вызывать ли B или C. У нас могут получиться два разных метода в классе D.

Это называется Diamond Problem (ромбическая проблема) - ситуация в ООП, когда класс наследуется от двух или более классов, которые имеют общий предок, что приводит к неясности - чей метод использовать в дочернем классе. Именно поэтому многие современные языки не поддерживают множественное наследование, а если два интерфейса содержат метод с одинаковой сигнатурой, то класс обязан явно переопределить его.
Python поддерживает множественное наследование и использует MRO (Method Resolution Order) — порядок разрешения методов, где Python сначала будет искать метод в B, потом в C и затем в A.
Иногда класс не должен быть наследуемым, чтобы предотвратить изменение его поведения. Это особенно важно для классов, реализующих важную логику. В некоторых языках есть ключевое слово, например final (Java), которое делает класс ненаследуемым - финальным:
Код ITЗагрузка примера кода…
Здесь класс Утилиты защищён от наследования.