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

18.1.3. Перехоплення винятків класового типу

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

Код програми 18.5. Демонстрація перехоплення винятків класового типу

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

#include <cstring> // Для роботи з рядковими типами даних

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

class myException {

public:

char strMas[80];

myException() { *strMas = 0;}

myException(char *s) { strcpy(strMas, s);}

};

int main()

{

int a, b;

try {

cout << "Введіть чисельник і знаменник: ";

cin >> а >> b;

if(!b) throw myException("Ділити на нуль не можна!");

else cout << "Частка дорівнює " << a/b << "\n";

}

catch(myException e) { // Перехоплення помилки

cout << e.strMas << "\n";

}

getch(); return 0;

}

Один з можливих результатів виконання цієї програми.

Введіть чисельник і знаменник: 10 0

Ділити на нуль не можна!

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

Безумовно, реальні винятки класового типу набагато складніші за клас myException. Як правило, створення винятків класового типу має сенс у тому випадку, якщо вони інкапсулюють інформацію, яка б дала змогу обробнику винятків ефективно справитися з помилкою і за змогою відновити роботоздатність програми.

18.1.4. Використання декількох catch-настанов

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

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

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

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

// Тут можливе перехоплення винятків різних типів.

void Xhandler(int test)

{

try {

if(test) throw test;

else throw "Значення дорівнює нулю.";

}

catch(int izm) {

cout << "Перехоплення! Виняток №: " << izm << "\n";

}

catch(char *str) {

cout << "Перехоплення рядка: " << str << "\n";

}

}

int main()

{

cout << "Початок.\n";

Xhandler(1);

Xhandler(2);

Xhandler(0);

Xhandler(3);

cout << "Кінець програми";

getch(); return 0;

}

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

Початок.

Перехоплення! Виняток №: 1

Перехоплення! Виняток №: 2

Перехоплення рядка: Значення дорівнює нулю.

Перехоплення! Виняток №: 3

Кінець програми

Як бачите, кожна catch-настанова відповідає тільки за винятки "свого" типу.

У загальному випадку catch-вирази перевіряються у порядку їх проходження, тобто виконується тільки той catch-блок, у якому тип заданого винятку збігається з типом винятку, що згенерувався. Вся решта catch-блоків ігнорується.

Перехоплення винятків базового класу

Важливо розуміти, як виконуються catch-настанови, пов'язані з похідними класами. Йдеться про те, що catch-вираз для базового класу "відреагує збігом" на винятки будь-якого похідного типу (тобто типу, виведеного з цього базового класу). Отже, якщо потрібно перехоплювати винятки як базового, так і похідного типів, то у catch-послідовності catch-настанову для похідного типу необхідно помістити перед catch-настановою для базового типу. Інакше catch-вираз для базового класу перехоплюватиме (крім "своїх") і винятки всіх похідних класів. Розглянемо, наприклад, наведену нижче програму.

Код програми 18.7. Демонстрація перехоплення винятків базових і похідних типів

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

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

class bClass { // Оголошення класового типу

};

class dClass: public bClass { // Оголошення класового типу

};

int main()

{

dClass derived;

try { throw derived; }

catch(bClass b_ob)

{cout << "Перехоплення винятку базового класу.\n";}

catch(dClass d_ob)

{cout << "Це перехоплення не відбудеться.\n";}

getch(); return 0;

}

Оскільки тут об'єкт derived – це об'єкт класу dClass, який виведений з базового класу bClass, то виняток типу derived завжди перехоплюватиметься першим catch-виразом; друга ж catch-настанова при цьому ніколи не виконається. Одні компілятори відреагують на такий стан речей застережливим повідомленням, інші можуть видати повідомлення про помилку. У будь-якому випадку, щоб виправити ситуацію, достатньо поміняти порядок слідування цих catch-настанов на протилежний.