Множинне успадкування
У C++ похідний клас може бути породжений із будь-якої кількості безпосередніх базових класів. Наявність у похідного класу більш ніж одного безпосереднього базового класу називається множинною спадщиною. Синтаксично множинне успадкування відрізняється від одиничного успадкування списком баз, що складається з більш ніж одного елемента.
При створенні об'єктів-представників похідного класу порядок розташування безпосередніх базових класів у списку баз визначає черговість виклику конструкторів замовчування.
Цей порядок впливає на черговість виклику деструкторів при знищенні цих об'єктів. Але ці проблеми, як і алгоритми виділення пам'яті для базових об'єктів, швидше за все, ставляться до питань реалізації. Навряд програміст повинен акцентувати на цьому особливу увагу.
Для наочного уявлення структури похідного класу також використовуються спрямовані ациклічні графи, схеми класів та об'єктів.
Як і раніше, нижній вузол направленого ациклічного графа, а також нижній рівень схем відповідає похідному класу і фрагменту об'єкта, що представляє похідний клас.
Такий фрагмент об'єкта ми називатимемо похідним фрагментом-представником даного класу.
Верхні вузли графа та верхні рівні схем класів та об'єктів відповідають базовим класам та фрагментам об'єктів, що представляють базові та безпосередні базові класи.
Ці фрагменти об'єкта ми називатимемо базовими та безпосередніми базовими фрагментами-представниками класу.
Ось як виглядає граф раніше наведеного як приклад похідного класу D:
А ось як видається структура похідного класу у вигляді неповної схеми класу. Базові класи розташовуються на цій схемі впорядку, що відповідає списку базових елементів описі бази похідного класу. Той самий порядок буде використаний при зображенні діаграм об'єктів. І це незважаючи на те, що порядок виклику конструкторів базових класів визначається конкретною реалізацією. За порядком виклику конструкторів базових класів можна спостерігати після визначення їх власних версій.
А ось і схема об'єкта похідного класу.
Перше, що впадає у вічі - це безліч однойменних змінних, "розкиданих" за базовими фрагментами об'єкта. Та й самих базових фрагментів тут є чимало.
Очевидно, що базові фрагменти-представники одного базового класу, що утворюють об'єкт, за своєю структурою невиразні між собою. Незважаючи на свою ідентичність, всі вони мають індивідуальну характеристику - положення щодо похідного фрагмента об'єкта.
При множинному наслідуванні актуальною стає проблема неоднозначності, пов'язана з доступом до членів базових класів. Доступ до члена базового класу є неоднозначним, якщо вираз доступу називає більше однієї функції, об'єкта (дані-члени класу є об'єктами), типу (про це пізніше!) чи перелічителя.
Наприклад, неоднозначність міститься в наступному операторі:
тут робиться невдала спроба зміни значення даного члена базового фрагмента об'єкта MyD. Вираз доступу MyD.xA називає одночасно дві змінних xA. Роздільна здатність неоднозначності зводиться до побудови такого виразу доступу, яке однозначно вказувало б функцію, об'єкт, тип (про це пізніше!) або перелічник.
Наше чергове завдання зводиться до опису однозначних способів доступу до даних-членів класу, які розташовані в різних базових фрагментах об'єкта. І тут мивперше стикаємося з обмеженими можливостями операції доступу.
Цей оператор забезпечує зміну значення даного члена базового фрагмента - представника класу B. Тут немає жодних проблем, оскільки безпосередній базовий клас B успадковує дані-члени базового класу A. Оскільки в класі B відсутні дані-члени з ім'ям x0, транслятор однозначно визначає приналежність цього елемент. Отже, доступ до цього члена базового класу A "з боку" безпосереднього базового класу B не становить особливих проблем.
А тепер змінюється значення даного-члена базового фрагмента - представника класу С. І знову ж таки транслятор однозначно визначає місце розташування змінної змінної. Змінна x0 була оголошена у безпосередньому базовому класі C. І операція доступу вказує на цю змінну. А ось спроба зміни значення змінної x0, розташованої в базовому фрагменті-представнику класу A "з боку" безпосереднього базового класу C приречена. Так, оператор
некоректний через неоднозначність співвідношення класу та його члена, оскільки незрозуміло, про який базовий фрагмент-представник класу A йдеться. Вирази доступу зі складеними кваліфікованими іменами, як, наприклад,
Операція:: залишає в "мертвій зоні" цілі фрагменти об'єктів. Однак можливість доступу до членів класу, які опинилися поза межами досяжності операції доступу все ж таки існує. Вона забезпечується покажчиками та операціями явного перетворення типу.
Ідея у тому, щоб, оголосивши покажчик на об'єкт-представник базового класу, спробувати його налаштувати з допомогою операцій явного перетворення типу відповідний фрагмент об'єкта похідного класу. У результаті недосяжні за допомогою операції доступу фрагментиоб'єкти перетворюються на безіменні об'єкти простої конфігурації. Доступ до членів у разі забезпечується звичайними операціями непрямого звернення. Розглянемо кілька рядків, які демонструють таку техніку роботи із недосяжними фрагментами.
Очевидно, що можна обійтися без поетапних перетворень та скористатися властивістю комутативності операції явного перетворення типу: