Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекція №6 Поліморфізм.doc
Скачиваний:
4
Добавлен:
16.11.2019
Размер:
86.02 Кб
Скачать

7

Раннє й пізнє зв'язування. Динамічний поліморфізм 1

Віртуальні функції 1

Віртуальні деструктори 3

Абстрактні класи й чисто віртуальні функції 4

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

Сигнатура це - ім'я функції, тип значення, що вертається, і список параметрів.

Раннє й пізнє зв'язування. Динамічний поліморфізм

В C++ поліморфізм підтримується двома способами.

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

По-друге, під час виконання програми він підтримується за допомогою віртуальних функцій. Віртуальна функція – це функція, виклик якої (і виконувані при цьому дії) залежить від типу об'єкта, для якого вона викликана. Об'єкт визначає, яку функцію потрібно викликати вже під час виконання програми. Цей вид поліморфізму називається динамічним поліморфізмом.

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

Для кожного поліморфного типу даних компілятор створює таблицю віртуальних функцій і вбудовує в кожний об'єкт такого класу схований вказівник на цю таблицю. Вона містить адреси віртуальних функцій відповідного об'єкта.

Оскільки об'єкти з віртуальними функціями повинні підтримувати й таблицю віртуальних функцій, то їх використання завжди веде до деякого підвищення витрат пам'яті й зниженню швидкодії програми. Якщо ви працюєте з невеликим класом, який не збираєтеся робити базовим для інших класів, то в цьому випадку немає ніякого сенсу у використанні віртуальних функцій.

Віртуальні функції

Функція, виклик якої залежить від типу об’єкта, для якого вона викликається, називається віртуальною. Вона позначається ключовим словом virtual.

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

class Coord

{

protected:

int x;

int y;

public:

Coord(int _x, int _y){x=_x;y=_y;}

void Output(){cout<<"\n Output class Coord"<<"x="<<x<<"y="<<y<<'\n';}

virtual void Print(){cout<<"\nPrint class Coord virtual"<<"x="<<x<<"y="<<y<<'\n';}

};

class Dot: public Coord

{

char name;

public:

Dot(int _x, int _y,char _name):Coord(_x,_y){name=_name;}

void Output(){cout<<"\n Output class Dot "<<"name="<<name;Coord::Output();}

void Print(){cout<<"\n Print class Dot "<<"name="<<name;Coord::Print();}

};

У наведеному прикладі оголошений базовий клас Coord і похідний клас Dot. Функція Print ( ) у похідному класі є віртуальної, тому що вона оголошена віртуальної в базовому класі Coord. Функція Print ( ) у похідному класі Dot перевизначає функцію базового класу. Якщо похідний клас не перевизначає функцію Print ( ), використовується реалізація за замовчуванням з базового класу.

Функція Output ( ) оголошена невіртуальної в базовому класі Coord і перевизначена в похідному класі Dot.

int _tmain(int argc, _TCHAR* argv[])

{

SetConsoleOutputCP(1251);

Coord *c;

Dot *d=new Dot(3,4,'A');

c=d;

cout<<"\nвказівник на базовий класс містить адресу похідного класу\n";

c->Output();

c->Print();

system("pause");

return 0;

}

При використанні вказівника на базовий клас, який реально вказує на об'єкт похідного класу, викликається невіртуальна функція базового класу.

Операція присвоєння c = d, яка використовує операнди різних типів (Coord* і Dot*) без перетворення, можлива тільки для вказівника на базовий клас у лівій частині. Зворотна операція присвоєння d = c неприпустима й викликає помилку синтаксису.

При виклику функції за допомогою вказівників і посилань, застосовуються наступне правила:

  1. виклик віртуальної функції виконується відповідно до типу об'єкта, адреса якого зберігає вказівник або посилання;

  2. виклик невіртуальної функції виконується відповідно до типу вказівника або посилання.

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

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

Використання вказівників на об'єкти, що містять віртуальні функції, дозволяє змінювати поведінку об'єкта в ході виконання програми за рахунок зміни його значення.