Обработка исключений – это стандартное языковое средство для реакции на аномальное поведение программы во время выполнения. C++ поддерживает единообразный синтаксис и стиль обработки исключений, а также способы тонкой настройки этого механизма в специальных ситуациях. Основы его поддержки в языке C++ описаны в главе 11, где показано, как программа может возбудить исключение, передать управление его обработчику (если таковой существует) и как обработчики исключений ассоциируются с try-блоками.

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

<p>19.2.1. Исключения, определенные как иерархии классов</p>

В главе 11 мы использовали два типа класса для описания исключений, возбуждаемых функциями-членами нашего класса iStack:

class popOnEmpty { ... };

class pushOnFull { ... };

В реальных программах на C++ типы классов, представляющих исключения, чаще всего организуются в группы, или иерархии. Как могла бы выглядеть вся иерархия для этих классов?

Мы можем определить базовый класс Excp, которому наследуют оба наши класса исключений. Он инкапсулирует данные и функции-члены, общие для обоих производных:

class Excp { ... };

class popOnEmpty : public Excp { ... };

class pushOnFull : public Excp { ... };

Одной из операцией, которые предоставляет базовый класс, является вывод сообщения об ошибке. Эта возможность используется обоими классами, стоящими ниже в иерархии:

class Excp {

public:

// напечатать сообщение об ошибке

static void print( string msg ) {

cerr

Иерархию классов исключений разрешается развивать и дальше. От Excp можно произвести другие классы для более точного описания исключений, обнаруживаемых программой:

class Excp { ... };

class stackExcp : public Excp { ... };

class popOnEmpty : public stackExcp { ... };

class pushOnFull : public stackExcp { ... };

class mathExcp : public Excp ( ... };

class zeroOp : public mathExcp { ... };

class divideByZero : public mathExcp { ... };

Последующие уточнения позволяют более детально идентифицировать аномальные ситуации в работе программы. Дополнительные классы исключений организуются как слои. По мере углубления иерархии каждый новый слой описывает все более специфичные исключения. Например, первый, самый общий слой в приведенной выше иерархии представлен классом Excp. Второй специализирует Excp, выделяя из него два подкласса: stackExcp (для исключений при работе с нашим iStack) и mathExcp (для исключений, возбуждаемых функциями из математической библиотеки). Третий, самый специализированный слой данной иерархии уточняет классы исключений: popOnEmpty и pushOnFull определяют два вида исключений работы со стеком, а ZeroOp и divideByZero – два вида исключений математических операций.

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

<p>19.2.2. Возбуждение исключения типа класса</p>

Теперь, познакомившись с классами, посмотрим, что происходит, когда функция-член push() нашего iStack возбуждает исключение:

void iStack::push( int value )

{

if ( full() )

// value сохраняется в объекте-исключении

throw pushOnFull( value );

// ...

}

* Выполнение инструкции throw инициирует несколько последовательных действий: Инструкция throw создает временный объект типа класса pushOnFull, вызывая его конструктор.

* С помощью копирующего конструктора генерируется объект-исключение типа pushOnFull – копия временного объекта, полученного на шаге 1. Затем он передается обработчику исключения.

* Временный объект, созданный на шаге 1, уничтожается до начала поиска обработчика.

Зачем нужно генерировать объект-исключение (шаг 2)? Инструкция

throw pushOnFull( value );

Перейти на страницу:

Похожие книги