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


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

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



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

int AnyFunctionO


if (conditionA)

throw "Big trouble!"; if (conditionB)

throw OverflowO; return 123;

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

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

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

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

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

Последнее замечание — ключевое. Функция AnyFunctionO обычно возвращает целочисленное значение, однако, если возникает исключительная ситуация она возвращает строку или объект класса Overflow. Только операторы catch могут воспринять эти возвращаемые значения. Если исключительных ситуаций не возникло, функция завершается нормально, возвращая (необязательно) значение типа, с которым объявляется функция, обратно оператору вызова этой функции.

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

catch (Error e) {

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

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

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

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

try {

int x = AnyFunctionO; > catch (Error e) {

e.ReportO;)

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

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

try {

FunctionAO; try {

FunctionBO; catch (Error e) {

e.ReportO; // ReportO

catch (Error e) { e.ReportO;}

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

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

try {

cout «"Here we go!" << endl; int x = AnyFunctionO;

cout «"x == " «x «endl; j

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

ЗАМЕЧАНИЕ

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

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

try {

cout «"Here we go!" «endl;

int x = AnyFunctionO;

cout «"x.== " «x << endl;

} ■

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 для всех возможных типов посылаемых объектов.

ЗАМЕЧАНИЕ

Исключительные ситуации упраздняют необходимость резервирования специальных возвращаемый значений для ошибок. Например, в классическом программировании на С и C++ для функции, возвращающей целое значение, может указываться, что сигнализирует об ошибке, прочие же возвращаемые значения — допустимые. В этом приеме нет ничего неправильного, просто резервирование специальных значений не всегда возможно. Рассмотрим функцию, суммирующую список целых значений. В этом случае все возвращаемые значения могут быть допустимыми, и невозможно зарезервировать одно из них для особого случая. Большинство программистов решают эту проблему, определяя глобальную переменную-флаг для ошибок, которая должна проверяться в программе обнаружения ошибок после вызова функции. Исключительные ситуации позволяют отказаться от такого запутанного способа обработки ошибок с помощью возврата объектов, представляющих состояния исключительных ситуаций без конфликтов с нормальными возвращаемыми значениями функции.

Программирование с исключительными ситуациями

Пример программы EXCEPT.CPP (листинг 15.16) демонстрирует использование исключительных ситуа­ций ANSI C++. Вы можете скомпилировать и запустить программу из DOS или WINDOWS. Из приглашения DOS следует ввести bec except, а затем имя программы для запуска получившегося в результате исполняемо­го файла EXCEPT.EXE. Или же из интегрированной среды скомпилируйте и запустите программу в качестве Easy Win-приложения.

ЗАМЕЧАНИЕ

Для демонстрации в модуле EXCEPT.CPP имеется оператор, который не выполняет никаких действий, что служит причиной предупреждений компилятора "Unread/able, code at line 78" (Недостижимый код и строке 78). Я включил этот оператор throw для отладки. Если вы сделаете ошибку, модифицировав программу (конечно, она хранится на диске, и вы не должны этого делать), оператор throw в строке 78 создаст объект класса Error с помощью вызова конструктора по умолчанию. Изучите объявление класса. Созданный таким способом, объект Error отобразит сообщение, свидетельствующее об ошибке в исходном коде.

Листинг 15.16. EXCEPT.CPP (использование исключительных ситуаций ANSI C++)

// Демонстрация исключительных ситуаций ANSI C++

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

// Прототипы функций

void Instruct();

double Pow(double b, double e);

double Power(double b, double e);

// Классы исключительных ситуаций class Error {

double b; // Основание

double e; // Показатель степени public:

ErrorQ

{ cout «"Error in source codei" «endl; }

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

void ReportO;

 

int main()

Instruct();

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.ReportO;
return -1;

return 0;

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";

// Подфункция возведения в степень double Pow(double b, double e) {

return exp(e * log(b)); >

// Результирующий b возведенный в степень е double Power(double b, double e)

<

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; }

throw ErrorO; // В этом месте будет предупреждение }

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

Error::Report() { cout «"Domain error:"

«" base:" «b

<< " exponent:" << e

«endl;

}

В EXCEPT реализуется функция PowerO, способная возвести любое действительное число в любую действительную степень. Конечно, два условия исключительной ситуации заставляют функцию возбуждать исключительную ситуацию.

• Возведение отрицательного числа в дробную степень.

• Возведение нуля в отрицательную степень.

Для обработки подобных ситуаций наилучшим образом подходят исключительные ситуации. Имеются та! же следующие альтернативы — прервать выполнение программы (плохо), возвратить специальное значение (не подходит) или установить глобальный флаг ошибки (плохой стиль программирования).

Вместо применения этих относительно неудачных решений, функция Power возбуждает исключите льну] ситуацию, представленную объектом класса Error. Например, при попытке возвести отрицательное число дробную степень функция Power выполняет следующий оператор, создающий объект класса Error, инициализированный значениями b и е:

throw Error(b, e);

Вернемся к функции main(). Функция Power вызывается внутри блока try, часть которого приведем еще раз

try {

double ba.se, exponent, result

//... запрашиваются основание и показатель степени

result = Power(base, exponent);

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

Если функция Power возбуждает исключительную ситуацию, присваивание переменной result и следующий оператор вывода пропускаются, а блок try немедленно завершается. Оператор catch следует сразу же за блоком try:

catch (Error& e) {

e.Report();

return -1;

}

return 0;

 

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

ЗАМЕЧАНИЕ

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

Итак, программа осуществляет полный контроль над исключительными ситуациями. Пример заканчивает работу с кодом завершения, если были ошибки, или 0, если ошибок не было. Это обычная практика для программ, хотя операционные системы DOS и Windows игнорируют возвращаемые программами значения.

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



Поделиться:


Последнее изменение этой страницы: 2016-08-01; просмотров: 174; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.225.149.32 (0.042 с.)