Урок №169. Множинне спадкування

  Юрій  | 

  Оновл. 25 Лют 2021  | 

 455

До сих пір ми розглядали тільки одиночні спадкування, коли дочірній клас має тільки одного батька. Однак C++ надає можливість множинного спадкування.

Множинне спадкування

Множинне спадкування дозволяє одному дочірньому класу мати кілька батьків. Припустимо, що ми хочемо написати програму для відстеження роботи вчителів. Учитель — це Human. Тим не менш, він також є Працівником (Employee).

Множинне спадкування може бути використано для створення класу Teacher, який успадковуватиме властивості як Human, так і Employee. Для використання множинного спадкування потрібно просто вказати через кому тип спадкування і другий батьківський клас:

Тут ми використовуємо спадкування типу public.

Проблеми з множинним спадкуванням

Хоча множинне спадкування здається простим розширенням одиночного спадкування, воно може призвести до безлічі проблем, які можуть помітно збільшити складність програм і зробити кошмаром подальшу підтримку коду. Розглянемо деякі з подібних ситуацій.

По-перше, може виникнути неоднозначність, коли кілька батьківських класів мають метод з одним і тим же ім’ям, наприклад:

При компіляції c54G.getID() компілятор дивиться, чи є у WirelessAdapter метод getID(). Цього методу у нього немає, тому компілятор рухається по “ланцюжку” спадкування вгору і дивиться, чи є цей метод в будь-якому з батьківських класів. І тут виникає проблема — getID() є як у USBDevice, так і у NetworkDevice. Отже, виклик цього методу призведе до неоднозначності і ми отримаємо помилку, тому що компілятор не знатиме яку версію getID() йому слід викликати.

Тим не менш, є спосіб обійти цю проблему. Ми можемо явно вказати, яку версію getID() слід викликати:

Хоча це рішення досить просте, але все може стати набагато складніше, якщо наш клас матиме від 4-х батьківських класів, які, в свою чергу, матимуть свої батьківські класи. Можливість виникнення конфліктів імен збільшується експоненціально з кожним доданим батьківським класом, і в кожному з таких випадків потрібно буде явно вказувати версії методів, які слід викликати, щоб уникнути можливості виникнення конфліктів імен.

По-друге, більш серйозною проблемою є «алмаз смерті» (або «алмаз приреченості»). Це ситуація, коли один клас має 2 батьківських класи, кожен з яких, в свою чергу, успадковує властивості одного і того ж батьківського класу. Ілюстративно ми отримуємо форму алмазу.

Наприклад, розглянемо наступні класи:

Сканери та принтери — це пристрої, які отримують живлення від розетки, тому вони наслідують властивості PoweredDevice. Однак ксерокс (Copier) включає в себе функції як сканерів, так і принтерів.

У цьому контексті виникає багато проблем, включаючи неоднозначність при виклику методів і копіювання даних PoweredDevice в клас Copier двічі. Хоча більшість з цих проблем можна вирішити за допомогою явного вказування, підтримка і обслуговування такого коду може призвести до непередбачуваних затрат часу. Ми поговоримо детально про способи вирішення проблеми “алмаз смерті” на відповідному уроці.

Чи варто використовувати множинне спадкування?

Більшість завдань, які вирішуються за допомогою множинного спадкування, можна вирішити і з використанням одиночного спадкування. Є об’єктно-орієнтовані мови програмування (наприклад, Smalltalk, PHP), які навіть не підтримують множинне спадкування. Багато відносно сучасних мов програмування, таких як Java і C#, обмежують класи одиночним спадкуванням звичайних класів, але допускають множинне спадкування інтерфейсних класів. Суть ідеї, яка забороняє множинне спадкування в цих мовах, полягає в тому, що це зайва складність, яка породжує більше проблем, ніж вигод.

Багато досвідчених програмістів вважають, що множинне спадкування в мові C++ слід уникати будь-якою ціною через потенційні проблеми, які можуть виникнути. Однак все ж залишається ймовірність, коли множинне спадкування буде кращим рішенням, ніж придумування дворівневих “костилів”.

Варто відзначити, що ви самі вже використовували класи, написані з використанням множинного спадкування, навіть не підозрюючи про це: такі об’єкти, як std::cin і std::cout бібліотеки iostream, реалізовані з використанням множинного спадкування!

Правило: Використовуйте множинне спадкування тільки в крайніх випадках, коли завдання не можна вирішити одиночним спадкуванням, або іншим альтернативним способом (без придумування “велосипеду”).

Оцінити статтю:

1 Зірка2 Зірки3 Зірки4 Зірки5 Зірок (2 оцінок, середня: 5,00 з 5)
Loading...

Залишити відповідь

Ваш E-mail не буде опублікований. Обов'язкові поля відмічені *