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

Розділ 4. Поліморфізм

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

Поліморфізм – це властивість коду С++ поводитися по-різному, у залежності від ситуації, що виникає в момент виконання.

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

class A

{

public:

virtual void Display() {puts("\nКлас A");}

};

class B: public A

{

public:

virtual void Display() {puts("\nКлас B");}

};

void show (A* a) {a->Display();}

Void main()

{

A * a = new A;

B * b = new B;

a->Display(); // використання функції A::Display()

b->Display(); // використання функції B::Display()

show(a); // використання функції A::Display()

show(b); // використання функції B::Display()

delete a,b;

}

Поліморфне поводження функції Display() у класах А та В не очевидно, якщо розглядати тільки функцію main(). Воно розглядається тільки у функції show(), у котрій неможливо знати, яка саме функція A->Display() або В->Display() буде викликатися. Якби не було слова virtual, то робота коду виглядала б таким чином:

show(a); // використання A::Display()

show(b); // використання A::Display()

У цьому випадку звертання до функції призводить до виклику A::Display().

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

У попередньому прикладі віртуальна функція В::Display() викликалася динамічно під час виконання функції show(). Отже, функція В::Display(), так сказати, віртуально перевизначила функцію А::Display().

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

Рис. 4.1. Дерево спадкування

Дереву спадкування на рис.4.1. відповідає такий код:

class A

{

public:

virtual void P(int, int);

};

class B:public A

{

public:

virtual void P(int, double);

};

void A::P(int a, int b) { printf("\n a = %d, b = %d", a, b);}

void B::P(int a, double b) { printf("\n a = %d, b = %lf", a, b);}

void show(A* a) { a-> P(3, 5);} // завжди викликає A::P(int, int)

Void main()

{

A* a = new A;

B* b = new B;

show(a); // викликає A::P(int, int)

show(b); // викликає A::P(int, int)

delete a,b;

}

4.2 Абстрактні класи

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

У свою чергу узгоджений інтерфейс відчиняє дорогу інтенсивного використання пізнього зв’язування і полегшує роботу програміста по обслуговуванню об’єктів під час виконання програми.

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

Для цього в С++ використовується спеціальний запис:

virtual void print() = 0; // чиста віртуальна функція, що не можна плутати з оголошенням порожньої віртуальної функції.

virtual void print() {}; // порожня віртуальна функція

Абстрактні класи створюються для потреб похідних класів. Це означає, що абстрактні класи знаходяться поруч із коренем ієрархії.

Приклад:

#include <iostream>

using namespace std;

class A

{

public:

virtual void PrintOn() = 0; //чиста віртуальна функція,

//яка робить клас А абстрактним.

};

class B: public A

{

public:

virtual void PrintOn() {puts("Привіт\n");}

};

class C: public A

{

public:

virtual void PrintOn() {puts("Окей\n");}

};