Перегрузка операторов
Вообще, оператор – это встроенная функция с определенным синтаксисом. Мы не можем переопределить операторы для уже существующих типов данных, но можем определить их для своих классов. Определим операторы для типа “российская денежная единица” – рубли и копейки:
// класс “денежная единица”, состоящая из рублей и копеек
class RURb
{
friend RURb operator+(RURb&, RURb&);
friend RURb operator++(RURb&);
public:
RURb(unsigned int a, unsigned int b);
protected:
unsigned int rub;
unsigned int kop;
};
// конструктор
RURb::RURb(unsigned int a, unsigned int b)
{
rub=a;
kop=b;
while (kop>99)
{
rub++;
kop-=100;
}
}
// оператор + складывает a и b и возвращает результат
// в виде нового объекта
RURb operator+( RURb& a, RURb& b)
{
unsigned int rub=a.rub+b.rub;
unsigned int kop=a.kop+b.kop;
RURb c(rub,kop);
return c;
}
// оператор ++ увеличения на 1 копейку
RURb operator++( RURb& a)
{
a.kop++;
while (a.kop>99)
{
a.rub++;
a.kop-=100;
}
}
// использование
int main(int arges, char *pArgs)
{
RURb d1(1,60); // конструкторы
RURb d2(2,50);
RURb d3(0,0);
d3=d1+d2; // действия
++d3;
return 0;
}
Оператор можно сделать и нестатической функцией-членом.
Обработка исключений
Исключения возникают при какой-либо ошибке в программе, а также при ее искусственной генерации в программе. Например, при попытке открыть файл с неверным именем операционная система сгенерирует исключение с соответствующим номером. Из программы мы можем сгенерировать исключение с помощью оператора throw. Примеры:
throw 123;
throw “Исключительная ситуация 2”;
Для обработки исключений используется оператор try … catch.
При возникновении исключения C++ первым делом копирует сгенерированный объект в некоторое нейтральное место. После этого просматривается конец текущего блока try. Если блок try в данной функции не найден, управление передается вызывающей функции, где и осуществляется поиск обработчика. Если и здесь не найден блок try, процесс повторяется далее, вверх по стеку вызывающих функций. Этот процесс называется разворачиванием стека. Важной особенностью разворачивания стека является то, что на каждом его этапе все объекты, которые выходят из области видимости, уничтожаются так же, как если бы функция выполнила команду return. Это оберегает программу от потери ресурсов и действий неуничтоженных объектов. Когда необходимый блок try найден, программа ищет первый блок catch (который должен находиться сразу за закрывающей скобкой блока try). Если тип сгенерированного объекта совпадает с типом аргумента, указанным в блоке catch, управление перелается этому блоку (при этом аргументу catch будет присвоено значение объекта исключения); если же нет, проверяется следующий блок catch. Если в результате подходящий блок не найден, программа продолжает поиск уровнем выше, пока не будет обнаружен необходимый блок catch. Если искомый блок так и не найден, программа аварийно завершается. Возможно написание catch (…). Это соответствует любому типу и значению объекта исключения.
Пример с генерацией своего исключения:
#include <iostream.h>
//factorial - вычисляет факториал
int factorial(int n)
{
// Поскольку функция не может работать с
// отрицательными n, мы сразу проверяем
// допустимость переданного аргумента
if (n<0) throw "Отрицательный аргумент";
// теперь вычислим факториал
int accum=1;
while(n>0)
{
accum*= n;
n--;
}
return accum;
}
int main(int arges, char *pArgs[])
{
try
{
// Эта строка генерирует исключение
сout<<"Факториал от -1 равен"<<factorial(-1)<<endl;
// Управление никогда не дойдет до этой строки
cout<<" Факториал от 10 равен "<<factorial(10)<<endl;
}
// управление будет передано сюда
catch (char *pError)
{
cout<<"Возникла ошибка: " <<pError<<endl;
}
return 0;
}
Пример с исключительной ситуацией при записи на диск:
#include <iostream.h>
#include <stdio.h>
#include <conio.h>
int main(int arges, char *pArgs[])
{
FILE *f;
try
{
// следующая строка вызовет исключительную ситуацию
// так как имя файла некорректно
f=fopen(”invalid+.dat”,”wt”);
// продолжение блока try
…
}
catch(…)
{
cout<<"Ошибка при открытии файла"<<endl;
}
}
