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

16.2.5. Суто віртуальні функції та абстрактні класи

Як ми уже зазначали вище, якщо віртуальна функція, яка не перевизначена у похідному класі, викликається об'єктом цього похідного класу, то використовується та її версія, що була визначена в базовому класі. Але у багатьох випадках взагалі немає сенсу давати визначення віртуальної функції в базовому класі. Наприклад, в базовому класі figUre(з попереднього прикладу) визначення функції showArea() – це просто заглушка. Вона не обчислює і не відображає площу жодного з об'єктів. Як буде показано згодом, під час створення власних бібліотек класів, у тому, що віртуальна функція не має значущого визначення у контексті базового класу, немає нічого незвичайного.

Суто віртуальна функція – це віртуальна функція, яка не має визначення в базовому класі.

Існує два способи оброблення таких ситуацій. Перший (він показаний у попередньому прикладі коду програми) полягає у забезпеченні функцією виведення застережливого повідомлення. Можливо, такий підхід і буде корисний у певних ситуаціях, але здебільшого він просто неприйнятний. Наприклад, можна уявити собі віртуальні функції, без визначення яких у існуванні похідного класу взагалі немає ніякого сенсу. Розглянемо клас triAngle. Він абсолютно даремний, якщо у ньому не визначити функцію showArea(). У цьому випадку варто створити метод, який би гарантував, що похідний клас дійсно містить усі необхідні функції. У мові програмування C++ для вирішення цього питання і передбачено суто віртуальні функції.

Суто віртуальна функція – це функція, яка оголошена в базовому класі, але є такою, що не має у ньому ніякого визначення. Тому будь-який похідний тип повинен визначити власну версію цієї функції, адже у нього просто немає ніякої можливості використовувати версію з базового класу (через її відсутність). Щоб оголосити суто віртуальну функцію, використовують такий загальний формат:

virtual тип ім'я_функції (список_параметрів) = 0;

У цьому записі під елементом тип маємо на увазі тип значення, що повертається функцією, а елемент ім'я_функції використовуване у програмі її ім'я. Позначення = 0 є ознакою того, що функція тут оголошується як суто віртуальна. Наприклад, в наступній версії визначення класу figUre функція showArea() вже представлена як суто віртуальна:

class figUre {

double x, y;

public:

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

virtual void showArea() = 0; // Суто віртуальна функція

};

Оголосивши функцію суто віртуальною, програміст створює умови, при яких похідний клас просто вимушений мати визначення власної її реалізації. Без цього компілятор видасть повідомлення про помилку. Наприклад, спробуйте скомпілювати цю модифіковану версію програми обчислення площ геометричних фігур, у якій з класу cirCle видалено визначення функції showArea().

Код програми 16.7. Демонстрація не коректної програми, яка у класі cirCle немає перевизначення функції showArea()

#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() = 0; // Суто віртуальна функція

};

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 {

// Відсутність визначення функції showArea()

// Викличе повідомлення про помилку.

};

int main()

{

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

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

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

cirCle С_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;

}

Якщо клас містить хоч би одну суто віртуальну функцію, то він називається абстрактним.

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