Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Бичков - Основи сучасного програмування.doc
Скачиваний:
69
Добавлен:
07.03.2016
Размер:
2.67 Mб
Скачать

Virtual int method1(float r);

virtual void method2(void);

virtual float method3(char*s);};

class child1:public Parent

{public:

virtual void method2(void);}

class child2:public child1

{public:

virtual float method3(char*s);}

Для цього прикладу ТВФ можна зобразити так:

//клас Parent:

virtual_table1->

parent::method1

parent::method2

parent::method3

//для Child1:

virtual_table2->

parent::method1

child1::method2

parent::method3

//Беремо до уваги однаковість зміщення.

//для Child2:

virtual_table3=>

parent::method1

child1::method2

child2::method3

Тоді виклик вигляду

child2*c;

c->method3(string");

компілятор перетворює на

(*(c=>virtual_table3[2]))(c,"string");

7.10.6. Віртуальні базові класи

Ієрархії класів та успадкування. Похідні та їх базові класи утворюють ієрархію, яка може бути надзвичайно складною навіть у відносно простих програмах. А якщо згадати ще й можливості множинного успадкування, то ситуація взагалі може вийти з-під контролю. Не дивно, що у складних ієрархіях класів виникають конфлікти. Крім уже розглянутих вище конфліктів імен, виникають і конфлікти дещо іншого характеру. Розглянемо такий приклад:

class A

{protected:

int data;

public:

void func(void){//тіло}};

class B: public A

{//...}

classC:public A

{//...}

class D:public B,public C

{//...}

main()

{D d;

d.func();}

Одразу виникає синтаксичне питання: яка функція func() викликається – успадкована класом В чи С? Формально тут присутній розглянутий вище конфлікт імен. Бачимо, що у випадку, коли один клас успадковується іншим кілька разів (через множинне успадкування), можуть виникнути негативні моменти. Такі помилки виявляються на етапі компіляції. У прикладі клас A успадковується у D два рази, будучи базовим для класів В i С. Очевидно, що проблеми можуть виникнути й у тому випадку, коли класи В та С мають конструктори, які iнiцiалiзують поле data. Тоді клас D також повинен мати конструктор, хоча б для того, щоб викликати конструктори базових класів. Однак при цьому виникне неоднозначність при iнiцiалiзацiї поля data.

Визначимо ще один клас:

class E:

public A,

public D

{\\...}

У цьому випадку також на етапі компіляції з'явиться помилка:

A is inaccessible becouse also in D

(А недоступний, оскільки він уже в D). Для виходу із таких ситуацій використовуються віртуальні базові класи.

Віртуальні базові класи. Синтаксично для оголошення базового класу віртуальним достатньо в базовому списку вказати ключове слово virtual перед атрибутом доступу:

class<ім’я похідного класу>:virtual<атрибут доступу><ім’я базового класу>,...

Семантично така конструкція вказує компілятору, що у випадку множинного успадкування береться до уваги лише одна копія базового класу. При цьому ліквідується небезпека повторного успадкування. Ключове слово virtual має бути присутнім у всіх випадках, де можливе повторне успадкування базового класу. Якщо в нашому прикладі оголосити базовий клас А віртуальним, то жодних негативних моментів, пов'язаних із повторним успадкуванням, не буде:

class A

{protected: