Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП_KAZYMYR.doc
Скачиваний:
18
Добавлен:
09.11.2019
Размер:
3.71 Mб
Скачать

3.3.1.Віртуальне успадкування

При множинному спадкуванні базовий клас не може бути заданий у похідному класі більше одного разу:

class D: A, B, B {...…}; // не припустимо

Однак базовий клас може бути переданий похідному класу більше одного разу побічно, наприклад, у такий спосіб:

class A {public: int i;};

class B: public A {...…};

class З: public A {...…};

class В: public B, public C {...…};

У наведеному прикладі кожний об'єкт класу D буде мати у своєму складі два об'єкти класу А. Це може привести до того, що при звертанні до змінного i класу А об'єкт класу D не буде знати змінну якого саме об'єкта класу А викликати. Для виключення даної колізії в передбачений варіант віртуального успадкування, коли для об'єкта-спадкоємця створюється не більше одного об'єкта кожного з наслідуваних класів. Для визначення віртуального успадкування перед ім'ям базового класу ставиться слово virtual:

class B: virtual public A {...…};

class З: virtual public A {...…};

С уть механізму віртуального успадкування полягає в тому, що при віртуальному успадкуванні об'єкт похідного класу містить схований покажчик на об'єкт віртуального базового класу. Цей покажчик компілятор неявно використовує для доступу до даних, успадкованих від віртуального базового класу. Схема побудови об'єкта похідного класу при звичайному й віртуальному успадкуванні показана на рис.3.5.

а) б)

Рис. 3.4. Схема побудови об'єкта похідного класу при звичайному й віртуальному спадкуванні: а) при звичайному спадкуванні, б) при віртуальному спадкуванні

3.3.2.Правило сумісності типів

Завдяки механізму успадкування, виникає можливість неявного перетворення типів, використовуючи для цього покажчики на базові класи. Правило сумісності типів при цьому полягає в наступному:

  1. Якщо клас У має public базовий клас А, то значення покажчика на клас У можна привласнити змінної типу “покажчик на клас А” без явного перетворення типів. Тобто, покажчик на нащадка може одночасно бути покажчиком на предка, але не навпаки; зворотне перетворення повинне бути явним:

сlass A {...…………};

сlass B: public A {...…………};

void main() {

B b;

A * aptr = &b; // неявне перетворення типів

B* bptr = aptr; // помилка

bptr = (B*) aptr; // явне перетворення типів

}

  1. Якщо базовий клас є private, то неявне приведення типів від нащадка до предка не робиться, тому що до загального елемента класу А є доступ тільки через покажчик на А, а не через покажчики на В:

сlass A { int m1;

public:

int m2;

…………};

class B: A {...…………};

void main()

{B b;

b..........2 = 2; // помилка, тому що m2 стала private

A* aptr = &b; // помилка

aptr = (A*) &b; // явне перетворення типів

aptr( m2 = 2; // допускається, тому що для покажчика aptr m2 public.

}

Таким чином, використовуючи явне перетворення типу можна обійти правило захисту доступу, але не можна одержати доступ до закритих змінним класу.

3.3.3.Використання конструкторів і деструкторів при успадкуванні

Механізм успадкування вносить свої особливості у використання конструкторів і деструкторів:

  1. Коли клас має один або більше базових класів, конструктори базових класів запускаються до того, як будуть викликані конструктори похідних класів. Причому конструктори базових класів викликаються в тій послідовності, у якій вони присутні при оголошенні базових класів. Так, для класу, оголошеного, як

сlass X: public Y, public Z {...…};

послідовність виклику конструкторів буде наступною:

Y(); Z(); X();

  1. Конструктори віртуальних базових класів запускаються до будь-яких конструкторів невіртуальних базових класів. Якщо ієрархія містить кілька віртуальних класів, то їхні конструктори викликаються в послідовності оголошення віртуальних базових класів. Після конструкторів віртуальних класів викликаються конструктори невіртуальних класів:

class X: public Y, virtual public Z {...…};

Послідовність виклику конструкторів: Z(); Y(); X();

  1. Якщо віртуальний клас є похідним від невіртуального, то спочатку повинен бути запущений конструктор цього невіртуального базового класу.

  2. Коли ієрархія містить множинне входження віртуального класу, то об'єкт даного класу конструюється тільки один раз. Однак, якщо є віртуальне й невіртуальне входження класу, то конструктор викликається один раз для всіх віртуальних входжень і один раз для всіх невіртуальних входжень даного класу.

  3. Деструктори викликаються в послідовності, зворотній конструкторам.

Нижче показаний приклад, що відображає правила виклику конструкторів і деструкторів:

class B;

class B2;

class L1: public B2, virtual public B;

class L2: public B2, virtual public B;

class L3: public L1, virtual public L2;

void main() { L3 l; }

Послідовність виклику конструкторів:

B(); B2(); L2(); B2(); L1(); L3()

Послідовність виклику деструкторів:

~L3();~L1();~B2();~L2();~B2();~B().

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]