Дещо про механізм віртуальних функцій

Екземпляр класу в С++ є неперервною областю в пам'яті. Покажчик на такий об'єкт містить її початкову адресу. Коли викликається функція-член (об'єкту посилається повідомлення), виклик компілюється у звичайний виклик функції із додатковим аргументом, який містить покажчик на об'єкт. Якщо наявний виклик функції

classname*object;

object->message(15);,

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

classname_message(object,15);

Механізм віртуальних функцій у С++ забезпечується за допомогою таблиць віртуальних функцій (ТВФ), які мають такі властивості:

1. ТВФ будується компілятором автоматично для кожного класу, який має віртуальні функції й містить їх адреси, доступні в цьому класі.

2. Кожний екземпляр класу містить скритий покажчик на його ТВФ.

3. Компілятор автоматично вставляє в початок конструктора класу фрагмент коду, який ініціалізує покажчик на ТВФ кожного класу.

4. Для будь-якої ієрархії класів адреса деякої віртуальної функції має одне й те саме зміщення у ТВФ кожного класу.

5. Під час виклику віртуальних функцій код, згенерований компілятором, перш за все знаходить покажчик віртуальної таблиціi, потім відбувається звертання до ТВФ і знаходиться адреса віртуальної функції, i лише після цього відбувається її безпосередній виклик. Наприклад:

Class Parent

{int value;

public:

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");

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

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

Class A

{protected:

int data;

public:

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

Class B: public A

{//...}

ClassC:public A

{//...}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: