If (coB)

If (coA)

Возбуждение нескольких исключительных ситуаций

Использование исключительных ситуаций

Исключительные ситуации представляются объектами, которые очень похожи на аргументы функции.

Это могут быть объекты любого типа, однако наиболее часто они представляют собой экземпляры класса.

Например, можно объявить класс Overflow, он не нуждается в каком-либо содержимом, необходимо лишь имя:

class Overflow { };

Можно послать экземпляр этого класса для возбуждения исключительной ситуации (предположим, внутри функции):

throw Overflow();

В этом операторе создается объект класса Overflow, который затем посылается обратно в место вызова функции.

Где-нибудь в другом месте программы можно перехватить исключительную ситуацию с помощью оператора catch:

catch (Overflow) {

cout « "Overflow detected!" << endl;

Одно только присутствие объекта Overflow свидетельствует о возбуждении исключительной ситуации.

Объект не обязан предпринимать каких-либо действий (хотя может).

Важно понять, что предыдущий оператор throw посылает объект класса Overflow, который перехватыва­ется оператором catch в другом месте программы.

Может быть, эту кон­цепцию легче будет понять, если снабдить перехватываемый объект именем, используя синтаксис, принятый в объявлениях списков параметров функций:

catch (Overflow overObject){

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

 

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

пример:

class Overflow { void Report()

{ cout << "Error: overflow" << endl; }

//В классе Overflow объявляется функция-член //ReportO, отображающая сообщение об //ошибке.

В операторе catch можно вызвать ReportO объекта исключительной ситуации для отображения сообщения об ошибке:

catch (Overflow overObject) {

overObject.Report();// Вызвать //функцию Report брошенного объекта

В функциях можно возбуждать объекты исключительных ситуаций различных типов для поддержки раз­личных условий исключительных ситуаций.

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

int AnyFun()

{


throw "Big trouble!";

throw Overflow();

return 123;}

Если условие coA справедливо (что бы оно ни значило), функция возбуждает строковую ис­ключительную ситуацию с сообщением "Big trouble!". Если выполняется условие coB, функция посы­лает объект класса Overflow, создаваемый в данном случае с помощью обращения к конструктору класса по умолчанию. Если же функция не обнаружила ошибок, она возвращается обычным образом, передавая значение 123 тому, кто ее вызвал.

три важных следствия из приведенного примера.

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

• Возбуждение исключительной ситуации немедленно завершает выполнение функции, в которой выполняется оператор throw. »

• Как подсказывают два предыдущих наблюдения, исключительные ситуации обеспечивают альтернативный механизм возврата для функций.

Последнее замечание — ключевое. Функция AnyFunO обычно возвращает целочисленное значение, однако, если возникает исключительная ситуация она возвращает строку или объект класса Overflow.

Только операторы catch могут воспринять эти возвращаемые значения.

Если исключительных ситуаций не возникло, функция завершается нормально, возвращая (необязательно) значение типа, с которым объявляется функция, обратно оператору вызова этой функции.

Можно поддерживать несколько типов объектов исключительных ситуаций с помощью серии операто­ров catch. Например, для обработки исключительных ситуаций для класса Error и строк м.б. следующие операторы catch один за другим:

catch (Error e) {

// Обработка исключительной ситуации для класса Error } catch (const char* message) {

// Обработка исключительной ситуации для строк }

Введение в блоки try

Для того чтобы принимать объекты исключительных ситуаций неко­торой функции, надо вызвать ее внутри блока try:

//Блок try содержит один или несколько //операторов, исключительные ситуации //которых вы хотите перехва­тывать.

try {

int x = AnyFun();}//вызов ф-ции

// Один или более операторов catch

//должны следовать за блоком try.

catch (Error e) {//если ф-ция

//АнyFun() возбудила искл.ситуацию

e.Report(); //

exit(-1);}

Блок try содержит один или несколько операторов, исключительные ситуации которых вы хотите перехва­тывать. Один или более операторов catch должны следовать за блоком try.

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

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

Например, блок try может иметь вложенные блок try и операторы catch в следующем гипотетическом примере, причем, если в функции FunctionAO возбу­ждает исключительная ситуация, программа полностью пропускает вложенный блок try:

try {

FunctionA(); //испытать ф-цию во //внешнем //блоке

try {//вложенный блок try //пропускается в случае искл.ситуации

FunctionB();//испытать ф-цию во //внутреннем //блоке

}

catch (Error e) {//перехват //искл.ситуации, возбуждаемой ф=ей //FunctionB();

e.Repor(); // вызвать ф-ю объекта //исключительной ситуации

}

}

catch (Error e) {//перехват //искл.ситуации, возбуждаемой ф=ей //FunctionA();

{ e.Report();} // вызвать ф-ю объекта //исключительной ситуации

Использование блоков try

В блоке try может быть несколько операторов (обычно так и бывает):

try {

cout « "message!" << endl;

int x = AnyFunction();

cout « "x == " « x « endl; }

В блоке try сначала отображается сообщение. Затем в нем вызывается функция AnyFunctionO, результат которой присваивается целочисленной переменной х.

Если в функции AnyFunction возникла исключительная ситуация, блок try немедленно завершается. Другими словами, любое условие исключительной ситуации при­водит к пропуску присваивания х и завершающего оператора вывода.

За блоком try должны следовать один или несколько операторов catch (иначе не имеет смысла использо­вать try). Вот более законченный пример того, как можно обработать несколько исключительных ситуаций, которые может возбудить функция, подобная AnyFunctionO:

try {

cout « "message!" << endl;

int x = AnyFunction();//Если функция за­//вершилась нормально, ее результат //присваивается переменной х,

cout « "x == " « x « endl; }

// если функция AnyFunctionO //возбуждает исключительную ситуацию, //выполнение блока try немедленно //прерывается, посланные объекты //перехватываются соответствующими //операторами catch,

catch (char* message) {

cout << "Error! -- " << message « endl;

exit(-1); // Необязательно }

catch (Overflow) {

cout « "Overflow!" « endl;

exit(-2); // Необязательно } // В этом месте программа продолжает выполнение как обычно

 

В этом более пространном коде сначала испытывается вызов функции AnyFunctionO. Если функция за­вершилась нормально, ее результат присваивается переменной х, которая отображается в следующем операто­ре записи в стандартный поток вывода. Если исключительных ситуаций не было, оба оператора catch пропус­каются, поскольку нет объектов исключительных ситуаций объявленных типов, которые нужно было бы пере­хватывать. Конечно, если функция AnyFunctionO возбуждает исключительную ситуацию, выполнение блока try немедленно прерывается, посланные объекты перехватываются соответствующими операторами catch, a именно тем из них, в котором объявлен параметр типа, соответствующего типу данных посланного объекта.

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

Вы можете вставить один, два, три или более операторов catch после блока try для обработки ис­ключительных ситуаций различных типов. В этом примере два оператора catch обрабатывают исключитель­ные ситуации для строк и класса Overflow. Любые другие типы исключительных ситуаций, не обрабатывае­мые операторами catch, передаются вверх по цепочке вызовов. Например, предположим, что функция AnyFunction также возбуждает исключительную ситуацию типа NewException. Если в функции g() был вы­зван упомянутый выше код, объект этой исключительной ситуации будет передаваться наверх в g(), так как в этом коде обрабатываются только исключительные ситуации типов char* и Overflow.

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