Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOAP.doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
494.59 Кб
Скачать

5.3. Перехват исключений

Когда с помощью throw генерируется исключение, функции исполнительной библиотеки C++ выполняют следующие действия:

1) создают копию параметра throw в виде статического объекта, который существует до тех пор, пока исключение не будет обработано;

2) в поисках подходящего обработчика раскручивают стек, вызывая деструкторы локальных объектов, выходящих из области действия;

3) передают объект и управление обработчику, имеющему параметр, совместимый по типу с этим объектом.

При раскручивании стека все обработчики на каждом уровне просматриваются последовательно, от внутреннего блока к внешнему, пока не будет найден подходящий обработчик.

Пример.

#include <iostream.h>

class Obj

{ public:

Obj (char c)

{ label = c;

cout << "Конструируем объект " << label << endl;

}

~Obj();

{

сout << "Ликвидируем объект " << label << endl;

}

protected:

char label;

};

void fl() ;

void f2();

void main()

{

Obj a('a');

try

{

Obj b('b');

fl();

}

catch(float f)

{

cout << "Исключение float" << endl;

}

catch(int i)

{

cout << "Исключение int" << endl;

}

catch (... )

{

cout << "Исключение..." << endl;

}

}

void f1()

{

try

{

Obj c('c');

f2 ();

}

catch(char* pMsg)

{

cout << " Исключение char*" << endl;

}

}

void f2()

{

Obj d('d') ;

throw 10;

}

В результате работы этой программы на экран будет выведен следующий текст:

Конструируем объект а //main

Конструируем объект Ь //try

Конструируем объект с //f1

Конструируем объект d //f2

Ликвидируем объект d //выход из f2 по throw int

Ликвидируем объект с //выход из f1

Ликвидируем объект b //выход из try

Исключение int //catch int

Ликвидируем объект а //выход из main

Пример.

#include <fstream>

#include <iostream>

using namespace std;

class Hello

{ public:

Hello () {cout<< “Hello!”<<endl;}

~Hello () {cout<< “Hello!”<<endl;}

}

void fl()

{ ifstream ifs(“test.dat”);

if (!ifs)

{

cout << “Генерируем исключение” << endl;

throw “Ошибка открытия файла ”;

}

}

void f2()

{

Hello h;

f1();

}

int main()

{

try

{

cout << “In try” << endl;

f2();

cout << “From try” << endl;

}

catch(int i)

{

cout << "Исключение int" << endl;

}

catch(const char *p)

{

cout << "Исключение const char* - " <<p<< endl;

return 1;

}

catch (... )

{

cout << "Исключение..." << endl;

}

return 0;

}

В результате работы этой программы на экран будет выведен следующий текст:

In try //

Hello! //конструктор

Генерируем исключение // f1

Bye! //выход из f1, деструктор Hello

Исключение const char* - Ошибка открытия файла //

Итак, за ключевым словом throw следует выражение, которое создает объект некоторого типа: throw работает с любым типом объекта. Это значит, что вы можно "бросать" любое количество информации. Рассмотрим приведенное ниже определение класса.

#include <iostream.h>

#include <string.h>

//Except — универсальный класс

//обработки исключительных ситуаций

class Except

{

protected:

char msg[80]; //сообщение об ошибке

char file[80]; //имя файла и строка, в которой возникла ошибка

int lineNum;

public:

Except(char* pMsg, char* pFile, int nLine)

{

strncpy(msg, pMsg, sizeof msg);

msg[sizeof msg — 1] = ' \0 ' ;

strncpy (file, pFile, sizeof file};

file[sizeof file - 1] = ' \0';

lineNum = nLine;

}

virtual void display(ostream & out)

{

out << "Ошибка < " << msg << ">\n";

out << "обнаружена в строке #" << lineNum <<

" файла" << file << endl;

}

};

Генерация исключения при этом будет выглядеть следующим образом:

throw Except("Отрицательный аргумент факториала",__FILE__, __LINE__);

Соответствующий блок catch выглядит довольно просто:

void myFunc()

{

try

{

//...любой вызов

}

catch(Except &x) //захват объекта Except

{

//используем встроенную функцию-член

х.display(cerr) ;

Блок catch перехватывает исключение Except а затем использует встроенную функцию-член display() для отображения сообщения об ошибке.

Объект cerr представляет собой поток вывода для сообщений об ошибках, т.е. почти то же, что и cout. Разница между cout и cerr существенна только для профессиональных программистов.

Класс Except является универсальным для сообщений об ошибках. Этот класс, конечно, может быть расширен другими подклассами. Например, можно определить класс InvArgExcep для хранения значения некорректного аргумента в дополнение к сообщению об ошибке.

class InvArgExcept: public Except

{

protected:

int invArg;

public:

InvArgExcept (int arg, char* pFile,int nLine):

Except("Неверный аргумент", pFile, nLine)

{

invArg = arg;

}

virtual void display(ostream& out)

{

Except::display(out);

cout << "Аргумент равен " << invArg << endl;

}

};

Несмотря на то что в блоке catch указан класс Except, исключение InvArgExcept будет успешно обработано, поскольку InvArgExcept является Excepе, а функция-член display() полиморфна.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]