Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Козак Н.В. Лекции Основы создания программ в Си...doc
Скачиваний:
24
Добавлен:
23.09.2019
Размер:
2.24 Mб
Скачать

Объекты-исключения

Объявлением исключения в catch-обработчике могут быть объявления типа или объекта. Классы исключений спроектированы так, что в объектах-исключениях при возбуждении сохраняется некоторая информация и если в объявлении исключения фигурирует такой объект, то инструкции внутри catch-обработчика могут обращаться к информации, сохраненной в объекте выражением throw.

// новый класс исключения:

// он сохраняет значение, которое не удалось поместить в стек

class pushOnFull

{

public:

pushOnFull( int i ) : _value( i ) { }

int GetValue()

{ return _value; }

private:

int _value;

}

Новый закрытый член _value содержит число, которое не удалось поместить в стек. Конструктор принимает значение типа int и сохраняет его в _value.

void iStack::push( int value )

{

if ( full() )

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

throw pushOnFull( value );

// ...

}

У класса pushOnFull появилась также новая функция-член value(), которую можно использовать в catch-обработчике для вывода хранящегося в объекте-исключении значения:

catch ( pushOnFull eObj )

{

cout << "ERROR: trying to push value " << eObj.GetValue();

cout << " on a full stack\n";

}

< М-2-7 > отсюда

Обратите внимание, что в объявлении исключения в catch-обработчике фигурирует объект eObj, с помощью которого вызывается функция-член GetValue() класса pushOnFull.

Объект-исключение всегда создается в точке возбуждения, даже если выражение throw – это не вызов конструктора и, на первый взгляд, не должно создавать объекта. Например:

enum EHstate { noErr, zeroOp, negativeOp, severeError };

enum EHstate state = noErr;

int mathFunc( int i )

{

if ( i == 0 )

{

state = zeroOp;

throw state; // создан объект-исключение

}

// иначе продолжается обычная обработка

}

В этом примере объект state не используется в качестве объекта-исключения. Вместо этого выражением throw создается объект-исключение типа EHstate, который инициализируется значением глобального объекта state. Если при входе в catch-обработчик исключения выясняется, что в нем объявлен объект, то он инициализируется копией объекта-исключения. Например, следующая функция calculate() вызывает определенную выше mathFunc(). При входе в catch-обработчик внутри calculate() объект eObj инициализируется копией объекта-исключения созданного выражением throw.

void calculate( int op)

{

try

{

mathFunc( op );

}

catch ( EHstate eObj )

{

// eObj - копия сгенерированного объекта-исключения

}

}

Повторное возбуждение исключения

Может оказаться так, что в одном предложении catch не удалось полностью обработать исключение. Выполнив некоторые корректирующие действия, catch-обработчик может решить, что дальнейшую обработку следует поручить функции, расположенной “выше” в цепочке вызовов. Передать исключение другому catch-обработчику можно с помощью повторного возбуждения исключения. Для этой цели в языке предусмотрена конструкция

throw;

которая вновь генерирует объект-исключение. Повторное возбуждение возможно только внутри составной инструкции, являющейся частью catch-обработчика:

catch ( exception eObj )

{

if ( canHandle( eObj ) )

// обработать исключение

return;

else

// повторно возбудить исключение, чтобы его перехватил другой

// catch-обработчик

throw;

}

При повторном возбуждении новый объект-исключение не создается. Это имеет значение, если catch-обработчик модифицирует объект, прежде чем возбудить исключение повторно. В следующем фрагменте исходный объект-исключение не изменяется.

enum EHstate { noErr, zeroOp, negativeOp, severeError };

void calculate( int op )

{

try

{

// исключение, возбужденное mathFunc(), имеет значение zeroOp

mathFunc( op );

}

catch ( EHstate eObj )

{

// что-то исправить

// пытаемся модифицировать объект-исключение

eObj = severeErr;

// предполагалось, что повторно возбужденное исключение будет

// иметь значение severeErr

throw;

}

Так как eObj не является ссылкой, то catch-обработчик получает копию объекта-исключения, так что любые модификации eObj относятся к локальной копии и не отражаются на исходном объекте-исключении, передаваемом при повторном возбуждении. Таким образом, переданный далее объект по-прежнему имеет тип zeroOp.

Чтобы модифицировать исходный объект-исключение, в объявлении исключения внутри catch-обработчика должна фигурировать ссылка:

catch ( EHstate &eObj )

{

// модифицируем объект-исключение

eObj = severeErr;

// повторно возбужденное исключение имеет значение severeErr

throw;

}