ООП C++_9
.pdfООП 2013
Глава 9.
Исключения
МГТУ им. Н.Э. Баумана Факультет Информатика и системы управления
Кафедра Компьютерные системы и сети Лектор: д.т.н., проф.
Иванова Галина Сергеевна
1
9.1 Механизм исключений С++
Механизм исключений предполагает автоматическое формирование специального блока информации при обнаружении аварийной ситуации.
Традиционный подход: |
Механизм исключений: |
if (p!=NULL) *p=3; |
__try {*p=3;} |
else <Действие по устранению |
__except (<Фильтр>) |
ошибки> |
{ Действия по устранению ошибки} |
Достоинство: позволяет группировать обработку ошибок в том месте, где возможно принятие решения об ее устранении:
Объект A |
Объект B |
|
__try |
? |
|
... |
||
|
||
__except |
|
2
Генерация исключений С++
В языках С и С++ используются разные стандарты обработки исключений.
Генерация исключений:
throw [<Тип>](<Аргументы>);
где <Тип> – тип или класс генерируемого значения; если тип не указан, то компилятор определяет его исходя из типа аргумента (обычно это один из встроенных типов);
<Аргументы> – одно или несколько выражений, значения которых будут использованы для инициализации генерируемого объекта.
Примеры:
а) throw (”Неверный параметр”); /* тип const char * с указанным
б) |
throw |
|
в кавычках значением */ |
(221); // тип const int с указанным значением |
|||
в) |
class |
E { //класс исключения |
|
|
public: int num; |
// номер исключения |
|
|
|
E(int n): num(n){} |
// конструктор класса |
};
… |
|
throw E(5); // тип исключения – класс E, значение – 5 |
3 |
|
Перехват и обработка исключений
try {<Защищенный код>}
catch (<Ссылка на тип>){<Обработка исключений>} При этом выполняются следующие правила:
1)исключение типа T будет перехватываться обработчиками типов T, const T, T& или const T&;
2)обработчики типа базового класса перехватывают исключения типа производных классов;
3)обработчики типа void* перехватывают все исключения типа указателя.
Блок catch, для которого в качестве типа указано «…» обрабатывает исключения всех типов.
Примеры:
try {<Операторы>} // выполняемый фрагмент программы catch (EConvert& A){<Операторы>} /* перехват исключений
типа EConvert */
catch (char* Mes){<Операторы>} //перехват исключений char* catch(…) {<Операторы>} //перехват остальных исключений4
Возобновление исключения
Если перехваченное исключение не может быть обработано, то оно
возобновляется. |
|
Пример: |
|
class E{}; |
// класс исключения |
void somefunc() |
|
{ if(<условие> throw Out(); }// генерация исключения void func()
{try { somefunc(true); }
catch(E& e){ if (<условие>) throw; } /* если здесь
исключение обработать нельзя, то возобновляем его */ } void mainfunc()
{try { func();}
catch(E& e){ … } } // здесь обрабатываем исключение
5
Доступ к аргументам исключения
Использование имени переменной в качестве параметра оператора catch позволяет операторам обработки получить доступ к аргументам исключения через указанное имя.
Пример: |
|
|
class E //класс исключения |
|
|
{ public: int num; |
// номер исключения |
|
E(int n): num(n){} |
// конструктор |
|
} |
|
|
… |
|
|
try { ... |
|
|
throw E(5); |
// генерируемое исключение |
|
...} |
|
|
catch (E& e){if (e.num==5) {…}} // получен доступ к полю
6
Последовательность обработки исключения
при генерации исключения происходит конструирование временного объекта исключения;
выполняется поиск обработчика исключения;
при нахождении обработчика создается копия объекта с указанным именем;
уничтожается временный объект исключения;
выполняется обработка исключения;
уничтожается копия исключения с указанным именем.
Поскольку обработчику передается копия объекта исключения, желательно в классе исключения с динамическими полями предусмотреть копирующий конструктор и деструктор.
7
Обработка объекта исключения (Ex9_1)
#include <conio.h> |
|
|
#include <stdio.h> |
|
|
class MyException |
|
|
{ protected: int nError; |
|
|
public: MyException(int nErr) {nError=nErr;} |
||
~MyException(){puts("destructor");} |
||
void ErrorPut(){printf("Error %d.\n",nError);} |
||
}; |
destructor |
|
int main(int argc, char* argv[]) |
||
Error 5. |
||
{ |
destructor |
|
try |
destructor |
|
{ |
program |
|
throw MyException(5); |
Press any key to continue |
|
} |
|
|
catch(MyException E){E.ErrorPut();} |
||
puts("program"); |
|
|
getch(); return 0; |
8 |
|
} |
|
Спецификация исключений
При объявлении функции можно указать, какие исключения она может генерировать:
throw(<тип>,<тип>…).
Пример:
void func() throw(char*,int){…} /*функция может генерировать исключения char* и int */
Спецификация исключений не считается частью типа функции и, следовательно, ее можно изменить при переопределении:
class ALPHA
{public: struct ALPHA_ERR{};
virtual void vfunc() throw(ALPHA_ERR){}
};
class BETA : public ALPHA { public:
void vfunc() throw(char *) {}
}; |
9 |
|
Уничтожение локальных переменных при обработке исключения (Ex9_2)
#include <iostream> |
При «раскручивании» стека |
|
|
using namespace std; |
локальные переменные |
|
|
void MyFunc( void ); |
уничтожаются |
|
|
class CTest |
|
|
|
{public: CTest(){}; |
|
|
|
|
~CTest(){}; |
|
|
|
const char *ShowReason() const |
|
|
}; |
{ return "Exception in CTest class."; } |
|
|
|
|
|
|
class CDtorDemo |
|
|
|
{public: CDtorDemo(); |
|
|
|
}; |
~CDtorDemo(); |
|
|
|
|
|
|
CDtorDemo::CDtorDemo() |
|
|
|
{ |
cout << "Constructing CDtorDemo." << endl;} |
|
|
CDtorDemo::~CDtorDemo() |
|
|
|
{ |
cout << "Destructing CDtorDemo." << endl;} |
10 |
|
|
|
|