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

Объявления исключительных ситуаций

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

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

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

void AnyFunction() throw(Error);

Следующее за именем функции и списком параметров (пустым в данном случае) выражение throw() ука­зывает, что функция AnyFunction() может возбуждать исключительные ситуации типа Error. Подобное объяв­ление указывает компилятору, что функции AnyFunctionO не разрешается возбуждать исключительные си­туации других типов.

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

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

void AnyFunction() throw(Error, char*, OtherType);

В предыдущем листинге EXCEPT.СРР обрабатываются все возможные исключительные ситуации, однако при обнаружении ошибки программа завершается. Несомненно, будет лучше, если операторы, вызвавшие ис­ключительную ситуацию в программе, будут повторяться, чтобы пользователь мог ввести корректные значения. В следующей модифицированной программе также демонстрируется, как писать код, обрабатываю­щий все возможные исключительные ситуации, даже те, которые не ожидались вовсе, возбуждаемые плохо документированными библиотечными функциями. Скомпилируйте и запустите листинг 15.17, как вы это уже делали с предыдущим листингом (из DOS или в виде EasyWin-приложения). Введите неверные значения в ответ на запросы программы. На рис. 15.1 демонстрируется результат работы программы.

 

Листинг 15.17. ЕХСЕРТ2.СРР (обработка ошибок с помощью исключительных ситуаций)

// Демонстрация обработки ошибок с помощью исключительных ситуаций

«include <iostream.h> «include <math.h>

// Неполное объявление класса исключительных ситуаций, необходимое // для того, чтобы на него могла сослаться функция Power()

class Error;

// Прототипы функций (отметьте объявленную ситуацию в функции Power)

void InstructO;

void Run();

double Pow(double b, double e);

double Power(double b, double e) throw(Error);

// Полное объявление класса объектов исключительной ситуации

class Error {

double b; // Base

double e; // Exponent public:

Error() { cout « "Error in source code!" « endl; }

Error(double bb, double ее) : b(bb), e(ee) { }

void ReportQ;

};

int main()

InstructO;

for (;;)

{ try {

Run();

cout « "Program is ending normally." « endl;

return 0; // Только если не было исключительных ситуаций

catch (...) { cout « "Error detected: Try again!" « endl;

}

}

}

Void Instruct(){

cout << "Power Demonstration\n\n";

cout « "This program displays the result of raising\n";

cout « "a value (base) to a power (exponent). To\n";

cout << "force an exception, enter a negative base\n";

cout « "and a fractional exponent (e.g. -4 and 1.5)\n";

cout « "Or, enter a zero base and an exponent less than\n";

cout « "zero.\n\n";

// Выполнить программ (повторно вызывается из main ())

void Run() { try {

double base, exponent, result;

cout « "base? ";

cin » base;

cout << "exponent? ";

cin >> exponent;

result = Power(base, exponent);

cout << "result == " « result << endl;

>

catch (Error& e) {

e.Report(); // Отобразить сообщение об ошибке throw e; // Передать исключительную ситуацию в место вызова

}

// Подфункция для Power double Pow(double b, double e) { return exp(e * log(b));

// Возвести b в степень е

double Power(double b, double e) throw(Error)

if (b > 0.0) return Pow(b, e);

if (b < 0.0) {

double ipart;

double fpart = modf(e, &ipart);

if (fpart == 0)

{ if (fmod(ipart, 2) != 0) // т.о. ipart - дополнение

return -Pow(-b, e); else

return Pow(-b, e); } else

throw Error(b, e);

} else {

if (e == 0.0) return 1.0;

if (e < 1.0) throw Error(b, e); return 0.0;

// Реализация функции-члена ReportO класса Error()

// Отобразить значения, вызвавшие исключительную ситуацию

void

Error:: ReportO

cout « "Domain error:"

« " base:" « b

« " exponent:" << e

« endl;

В приведенном листинге по сравнению с предыдущим сделано несколько модификаций. Во-первых, в нем сделано неполное объявление класса в строке 8. Это позволяет функциям ссылаться на класс, даже ес­ли на данном этапе объявлено только его имя. Например, функция PowerO использует выражение throw для сигнализации о том, что она может посылать объект исключительной ситуации класса Error (и только объект этого класса).

После прототипов функций в программе объявление класса Error завершается. Это тот же класс, который использовался в первоначальном листинге.