Исключения в конструкторах
Оба числа отличны от нуля;
Оба числа неотрицательны;
Следует отметить, что механизм обработки исключений является общим средством управления программой, а именно средством передачи управления специальному коду в вызывающем модуле.
Пример применения механизма исключений (из Подбельского) при определении функции определения наибольшего общего делителя (НОД) двух целых чисел (алгоритм Евклида):
· если x==y, то ответ найден, НОД = x;
· если x<y, то y заменяется значением y-x;
· если x>y, то x заменяется значением x-y;
· алгоритм применим при соблюдении условий
Этим ситуациям соответствуют два исключения. В первом случае исключением будет объект библиотечного класса string. Во втором случае, когда появляется нулевой параметр, в качестве исключения посылается значение второго, возможно ненулевого параметра, типа int.
#include <iostream>
#include <string>
using namespace std;
int GCD (int x, int y) {
if (x==0) throw y;
if (y==0) throw x;
if(x<0) throw string(“\nNegative parameter 1”)
if(y<0) throw string(“\nNegative parameter 2”)
while(x!=y) {
if(x>y) x=x-y;
else y=y-x;
}
return x;
}
int main() {
try{
cout<<”GCD(77,55) = ”<<GCD(77,55)<<endl;
cout<<”GCD(0,5) = ”<<GCD(0,5)<<endl;
cout<<”GCD(-7,4) = ”<<GCD(-7,4)<<endl;
}
catch(const string msg){
cout<<msg<<endl;
}
catch(const int ex){
cout<<” One parameter is ZERO!”;
cout<<” Another parameter equals “<<ex<<endl;
}
return 0;
}
Результат выполнения программы:
GCD(77,55)=11
One parameter is ZERO! Another parameter equals 5
В теле функции перед циклом, реализующем алгоритм - четыре оператора посылки исключений, которые выполняются при нарушении условий выполнимости алгоритма. Первые два оператора посылают исключения типа int, два следующих –объекты типа string.
В основной программе в блоке try три обращения к функции GCD(), причем, только первое не содержит ошибочных параметров.
Первый обработчик ловит исключение типа string, второй – типа int.
При втором вызове с нулевым параметром посылается исключение типа int, и после его обработки выполнение программы завершается, управление не передается в блок try.
Третий вызов функции вообще не выполняется.
В данном примере в качестве исключений использованы стандартные и библиотечные типы (int, string).
Намного удобнее в качестве исключения использовать объекты пользовательских классов.
Модифицируем пример, вводя специальный класс для исключений.
#include <iostream>
#include <string>
using namespace std;
struct DATA { //класс объектов - исключений
int n, m;
string s;
DATA (int x, int y, string str): //конструктор
n(x), m(y),s(str) { }
};
int GCD (int x, int y) {
if (x==0 | | y==0 ) throw DATA(x, y, ”ZERO!”);
if(x<0) throw DATA(x, y, “Negative parameter 1”)
if(y<0) throw DATA(x, y, “Negative parameter 2”)
while(x!=y) {
if(x>y) x=x-y;
else y=y-x;
}
return x;
}
int main() {
try{
cout<<”GCD(77,55) = ”<<GCD(77,55)<<endl;
cout<<”GCD(0,5) = ”<<GCD(0,5)<<endl;
cout<<”GCD(-7,4) = ”<<GCD(-7,4)<<endl;
}
catch(DATA d){
cerr<<d.s<<” x= “<<d.n<<”, y= “<<d.m<<endl ;
}
return 0;
}
Результат выполнения программы:
GCD(77,55)=11
ZERO! x=0, y= 5
Последнее обращение GCD(-7,4) не выполнено.
Исключения формируются как объекты специального класса DATA, который определен как структура с общедоступными полями.
Объекты класса DATA формируются в одной функции, но доступны в другой функции. Это особое свойство исключений, они создаются как статические объекты в одном блоке, но доступны в другом.
Достоинством исключений является временной разрыв между разработкой функции, генерирующей исключение, и определением алгоритмов обработки исключения.
После обработки исключения нельзя вернуться в блок, откудо исключение было послано!
Механизм исключений предназначен только для обработки синхронных событий, то есть таких событий, которые произошли в процессе выполнения программы, а не привнесены внешними воздействиями, например, отключение питания компьютера не удастся обработать как исключение.
Так как обработчики исключений выполняются последовательно, то обработчик без параметров следует располагать в конце последовательности!
После него никакой обработки исключений уже не будет.
Стандартом введена новая форма генерации и обработки исключений в конструкторах классов.
Внешнее определение конструктора может иметь такой вид:
имя_класса::имя_класса (спецификация параметров)
try: список инициализаторов
{операторы тела конструктора}