C++. Бархатный путь. Часть 2
Страница 47. Интерактивный вычислитель частного от деления двух плавающих чисел


 

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

Представляющий исключение класс 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(); /* Исключения не работают! */
}

Всё. Приехали. Можно расслабиться. Можно постоять на берегу океана. Послушать шум ветра в соснах. Посмотреть на касаток в холодной прозрачной воде. Только недолго. Впереди ждут великие дела.

 

 
Следующая статья »