Страница 47 из 48 На очереди ещё одна простая программа. Это уже не полигон. Это интерактивный вычислитель частного от деления двух плавающих чисел. Эта программа в бесконечном цикле запрашивает значения делимого и делителя, а в случае возникновения исключительной ситуации возбуждает исключение. В момент возбуждения исключения, пользователю предоставляется возможность принятия решения относительно дальнейшего продолжения вычислений. Представляющий исключение класс MyDivideByZeroError обладает всем необходимым набором элементов для эффективного взаимодействия с системой управления исключениями. Он располагает конструктором умолчания для возбуждения исключения. Там же имеется конструктор копирования для инициализации соответствующего параметра в блоке перехвата исключения. Есть и деструктор, который обеспечивает освобождение динамической памяти. #include <iostream.h> #include <string.h> #define YESMESS "Мы продолжаем." #define NOMESS "Мы завершаем." class MyDivideByZeroError { char *MyErrorMessage; public: char ContinueKey; MyDivideByZeroError(): MyErrorMessage(NULL) { char YesKey; cout << "Зафиксировано деление на нуль." << endl; cout << "Принимать экстренные меры? (Y/N) >> "; cin >> YesKey; if ( YesKey == 'Y' || YesKey == 'y' ) { ContinueKey = 1; MyErrorMessage = strdup(YESMESS); } else { ContinueKey = 0; MyErrorMessage = strdup(NOMESS); } } MyDivideByZeroError(const MyDivideByZeroError& CopyVal) { ContinueKey = CopyVal.ContinueKey; MyErrorMessage = strdup(CopyVal.MyErrorMessage); } ~MyDivideByZeroError() { if (MyErrorMessage) delete(MyErrorMessage); } void PrintMessage() { cout << MyErrorMessage << endl; } }; float Dividor(float, float) throw(MyDivideByZeroError); void main() { float MyVal1, MyVal2; for (;;) { //__ Начало контролируемого блока __________________________________. try { cout << "========================================" << endl; cout << "MyVal1 >> "; cin >> MyVal1; cout << "MyVal2 >> "; cin >> MyVal2; cout << "Считаем... " << Dividor(MyVal1, MyVal2) << endl; cout << "Получилось! "; } catch (MyDivideByZeroError MyExcept) { MyExcept.PrintMessage(); if (MyExcept.ContinueKey == 0) { cout << "Надоело воевать с ошибками! Уходим." << endl; break; } } //__ За пределами контролируемого блока ____________________________. cout << "Уже за пределами блока. Мы продолжаем..." << endl; } } float Dividor(float Val1, float Val2) throw(MyDivideByZeroError) { if (Val2 == 0.0) throw MyDivideByZeroError(); return Val1/Val2; }
И, наконец, пример замещения функций unexpected и terminate. Последняя программа в этой книге. #include <iostream.h> #include <except.h> #define MAXERR 5 class MaxError; class MyError { public: MyError() { CounterError++; if (CounterError > MAXERR) { cout << " Здесь MyError()... throw MaxError()!" << endl; throw MaxError(); } else { cout << " Здесь MyError()... CounterError++!" << endl; } } void ErrSay() { cout << " Здесь ErrSay(): " << CounterError << endl; } static int CounterError; }; int MyError::CounterError = 0; class MaxError { public: MaxError() { if (CounterMaxError == 0) { /* MaxError один раз может подправить значение счётчика MyError::CounterError. */ CounterMaxError++; MyError::CounterError -= 2; cout << "Здесь MaxError().. MyError::CounterError-= 2;" << endl; } else { cout << " Здесь MaxError()... ###" << endl; } } static int CounterMaxError; }; int MaxError::CounterMaxError = 0; void RunnerProcessor(); void Run() throw(MyError); void MyUnex(); void MyTerm(); void main() { unexpected_function OldUnex; terminate_function OldTerm; OldUnex = set_unexpected(MyUnex); OldTerm = set_terminate(MyTerm); /* Мы замещаем функции unexpected() и terminate(). Адресные переменные нужны для того, чтобы запомнить адреса старых функций. В случае необходимости, их можно восстановить: set_unexpected(OldUnex); set_terminate(OldTerm); */ RunnerProcessor(); } void RunnerProcessor() { for (;;) { try { Run(); } catch (MyError err) { err.ErrSay(); } } } void Run() throw(MyError) { cout << "Работает Run()..." << endl; throw MyError(); } void MyUnex() { /* Мы всё ещё находимся в пределах try-блока. */ cout << "Это MyUnex()..." << endl; throw MyError(); } void MyTerm() { int MyTermKey = 0; /* Вышли из try-блока. Включилась система автоматического торможения. */ for ( ; MyTermKey < 5; ) { cout << "Это MyTerm()........................" << MyTermKey << endl; MyError::CounterError = 0; MaxError::CounterMaxError = 0; RunnerProcessor(); MyTermKey += 1; /* Цикл здесь уже не циклится! */ } MaxError::CounterMaxError = 0; throw MyError(); /* Исключения не работают! */ }
Всё. Приехали. Можно расслабиться. Можно постоять на берегу океана. Послушать шум ветра в соснах. Посмотреть на касаток в холодной прозрачной воде. Только недолго. Впереди ждут великие дела. |