Возможности механизма обработки исключений становятся больше, если в качестве исключений использовать иерархии классов. В этом разделе мы расскажем, как писать программы, которые умеют возбуждать и обрабатывать исключения, принадлежащие таким иерархиям.
19.2.1. Исключения, определенные как иерархии классов
В главе 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 – два вида исключений математических операций.
В последующих разделах мы рассмотрим, как возбуждаются и обрабатываются исключения, представленные классами в нашей иерархии.
19.2.2. Возбуждение исключения типа класса
Теперь, познакомившись с классами, посмотрим, что происходит, когда функция-член push() нашего iStack возбуждает исключение:
void iStack::push( int value )
{
if ( full() )
// value сохраняется в объекте-исключении
throw pushOnFull( value );
// ...
}
* Выполнение инструкции throw инициирует несколько последовательных действий: Инструкция throw создает временный объект типа класса pushOnFull, вызывая его конструктор.
* С помощью копирующего конструктора генерируется объект-исключение типа pushOnFull – копия временного объекта, полученного на шаге 1. Затем он передается обработчику исключения.
* Временный объект, созданный на шаге 1, уничтожается до начала поиска обработчика.
Зачем нужно генерировать объект-исключение (шаг 2)? Инструкция
throw pushOnFull( value );
создает временный объект, который уничтожается в конце работы throw. Но исключение должно существовать до тех пор, пока не будет найден его обработчик, а он может находиться намного выше в цепочке вызовов. Поэтому необходимо скопировать временный объект в некоторую область памяти (объект-исключение), которая гарантированно существует, пока исключение не будет обработано. Иногда компилятор создает объект-исключение сразу, минуя шаг 1. Однако стандарт этого не требует, да и не всегда такое возможно.
Поскольку объект-исключение создается путем копирования значения, переданного инструкции throw, то возбужденное исключение всегда имеет такой же тип, как и это значение:
void iStack::push( int value ) {
if ( full() ) {
pushOnFull except( value );
stackExcp *pse =
throw *pse; // объект-исключение имеет тип stackExcp