Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
+ООП_Навч_посібник.doc
Скачиваний:
7
Добавлен:
01.07.2025
Размер:
6.58 Mб
Скачать

16.2.4. Приклад застосування віртуальних функцій

Щоб Ви могли отримати уявлення про силу принципу "один інтерфейс, багато методів", розглянемо таку коротку програму. Вона створює базовий клас figUre, призначений для зберігання розмірів різних двовимірних об'єктів і обчислення їх площ. Функція setDim() є стандартною функцією-членом, оскільки ця операція підходить для всіх похідних класів. Проте функція showArea() оголошена як віртуальна, оскільки методи обчислення площі різних об'єктів будуть різними. Програма використовує базовий клас figUre для виведення двох спеціальних класів rectAngle і triAngle.

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

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

class figUre {

protected:

double x, y;

public:

void setDim(double izm, double jzm) { x = izm; y = jzm;}

virtual void showArea() {

cout << "У цьому класі виразу для обчислення "

<< "площі не визначено.\n";}

};

class triAngle : public figUre {

public:

void showArea() {

cout << "Трикутник з висотою " << x << " і основою " << y

<< " має площу " << х * 0.5 * y << ".\n";}

};

class rectAngle : public figUre {

public:

void showArea() {

cout << "Прямокутник розмірами " << х << " х " << y

<< " має площу " << х * y << ".\n";}

};

int main()

{

figUre *p; // Створення покажчика на об'єкт базового типу

triAngle T_ob; // Створення об'єктів похідних типів

rectAngle R_ob; // Створення об'єкта похідного типу

p = &T_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

p = &R_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

getch(); return 0;

}

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

Трикутник з висотою 10 і основою 5 має площу 25.

Прямокутник розмірами 10 х 5 має площу 50.

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

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

class cirCle : public figUre {

public:

void showArea() {

cout << "Круг з радіусом " << x

<< " має площу " << 3.14 * х * х;}

};

Перш ніж випробувати клас cirCle в роботі, розглянемо уважно визначення функції showArea(). Звернемо Вашу увагу на те, що в ній використовується тільки одне значення змінної х, яка повинна містити радіус круга1. Проте, згідно з визначенням функції setDim(), у класі figUre їй передається два значення, а не одне. Оскільки класу cirCle не потрібне друге значення, то що ми можемо зробити? Є два способи вирішити цю проблему. Перший (і одночасно найгірший) полягає у тому, що ми могли б, працюючи з об'єктом класу cirCle, просто викликати функцію setDim(), передаючи їй як другий параметр фіктивне значення. Основний недолік цього методу – відсутність чіткості у задаванні параметрів і необхідність пам'ятати про спеціальні винятки, які порушують дію принципу: "один інтерфейс, багато методів".

Є вдаліший спосіб вирішення цього питання, який полягає у наданні параметру функції setDim() значення, що діє за замовчуванням. У цьому випадку під час виклику функції setDim() для круга потрібно задавати тільки радіус. Під час виклику ж функції setDim() для трикутника або прямокутника задають обидва значення. Нижче показано програму, у якій реалізований цей метод.

Код програми 16.6. Демонстрація надання параметру віртуальної функції значення, що діє за замовчуванням

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

class figUre {

protected:

double x, y;

public:

void setDim(double izm, double jzm=0) { x = izm; y = jzm;}

virtual void showArea() {

cout << "Для цього класу вираз обчислення "

<< "площі не визначено.\n";}

};

class triAngle : public figUre {

public:

void showArea() {

cout << "Трикутник з висотою " << x << " і основою " << y

<< " має площу " << х * 0.5 * y << ".\n";}

};

class rectAngle : public figUre {

public:

void showArea() {

cout << "Прямокутник розмірами " << х << " х " << y

<< " має площу " << х * y << ".\n";}

};

class cirCle : public figUre {

public:

void showArea() {

cout << "Круг з радіусом " << x

<< " має площу " << 3.14 * x * x << ".\n";}

};

int main()

{

figUre *p; // Створення покажчика на об'єкт базового типу

triAngle T_ob; // Створення об'єкта похідного типу

rectAngle R_ob; // Створення об'єкта похідного типу

cirCle C_ob; // Створення об'єкта похідного типу

p = &T_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

p = &R_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

p = &C_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(9.0);

p->showArea();

getch(); return 0;

}

У процесі виконання ця програма відображає на екрані такі результати:

Трикутник з висотою 10 і основою 5 має площу 25.

Прямокутник розмірами 10 х 5 має площу 50.

Круг з радіусом 9 має площу 254.34.

Варто знати! Хоча віртуальні функції синтаксично прості для розуміння, їх справжні можливості неможливо продемонструвати на коротких прикладах. Як правило, потужність поліморфізму виявляється у великих складних системах. У міру засвоєння C++ Вам ще не раз буде надано можливість переконатися в їх корисності.