- •Объектно-ориентированное программирование:
- •Содержание
- •Новый тип данных – класс
- •1.2. Доступность компонентов класса
- •1.3. Конструктор и деструктор
- •1.4.4. Статические члены класса
- •1.4. Компоненты-данные и компоненты-функции
- •1.4.1. Данные – члены класса
- •1.4.2. Функции – члены класса
- •1.4.3. Константные компоненты-функции
- •Указатели на компоненты класса
- •1.5.1. Указатели на компоненты-данные
- •1.5.2.Указатели на компоненты-функции
- •1.6. Указатель this
- •1.7. Друзья классов
- •7.1. Дружественная функция
- •1.7.2. Дружественный класс
- •1.8. Определение классов и методов классов
- •2. Наследование
- •2.1. Определение производного класса
- •2.2. Конструкторы и деструкторы производных классов
- •2.3. Виртуальные функции
- •2.4. Абстрактные классы
- •2.5. Включение объектов
- •2.6. Включение и наследование
- •2.7. Множественное наследование
- •2.8. Локальные и вложенные классы
- •2.9. Пример программы для Microsoft Visual Studio
- •2.10. Упражнения
- •3. Перегрузка операций
- •3.1. Перегрузка унарных операций
- •3.2. Перегрузка бинарных операций
- •3.4. Перегрузка операции вызова функции
- •3.5. Перегрузка операции присваивания
- •3.6. Перегрузка операции new
- •3.7. Перегрузка операции delete.
- •3.8. Основные правила перегрузки операций
- •3.9. Примеры программ
- •4. Шаблоны функций и классов
- •4.1. Шаблоны функций
- •4.2. Шаблоны классов
- •4.3. Компонентные функции параметризованных классов
- •4.4. Примеры программ.
- •5. Обработка исключительных ситуаций
- •5.2. Получение дополнительной информации об исключении
- •5.3. Определение типа исключения
- •5.4. Иерархия исключений
- •5.5. Спецификация функций, обрабатывающих исключения
- •6. Потоковые классы
- •6.1. Библиотека потоковых классов
- •6.3. Стандартные потоки ввода-вывода
- •6.4. Форматирование
- •6.5. Манипуляторы
- •6.6. Ввод-вывод объектов пользовательских классов
- •6.7. Определение пользовательских манипуляторов
- •6.8. Пользовательские манипуляторы с параметрами
- •6.9. Использование макросов для создания манипуляторов
- •6.10. Состояние потока
- •6.11. Неформатированный ввод-вывод
- •6.12. Файловый ввод-вывод
- •7.1. Пространство имен
- •7.2. Динамическая идентификация типов
- •7.3. Безопасное приведение типа
- •8. Стандартная библиотека шаблонов
- •8.1. Введение в stl
- •Парадигму обобщенного программирования можно сформулировать следующим образом:
- •8.2. Итераторы
- •8.3. Классы-контейнеры
- •Iterator find(const key_type&k)
- •Iterator lower_bound(const key_type&k)
- •Iterator upper_bound(const key_type&k)
- •8.4. Контейнер vector
- •8.5. Многомерные массивы
- •8.6. Ассоциативные контейнеры
- •8.7. Объекты-функции
- •8.8. Алгоритмы
- •I. Немодифицирующие операции
- •II. Модифицирующие операции
- •III. Сортировка
- •IV. Работа с множествами
- •V. Минимумы и максимумы
- •VI. Перестановки
5.2. Получение дополнительной информации об исключении
Передача такой информации производится через дополнительные поля, которые указываются в классе-индикаторе исключения. Вся необходимая информация передается в обработчик исключения с помощью соответствующего объекта (например, объекта класса range).
Пример 5.2.1
Добавим в класс string вложенный класс range, поле которого i будет хранить значение ошибочного индекса.
struct range
{
int i;
range(int s):i(s){};
};
При ошибке создается объект range,
char& string :: operator[](int s)
{if((s<0)||(s>size)) throw range(s); return p[s];}
Теперь в выражении throw range(s) в поле i объекта класса range будет записано значение ошибочного индекса s.
Для того чтобы в обработчике исключения проанализировать значение ошибочного индекса, необходимо задать имя объекту-индикатору исключения:
try{/* контролируемый код*/}
catch(string : : range ob)
{cerr<<”Неверный индекс: ”<<ob.i<<endl;}
Выражение (string : : range ob) объявляет тип исключения (string : : range) и может дополнительно задавать имя объекта исключения (ob).
Полностью программа выглятит так
#include <iostream.h>
#include<stdio.h>
#include<windows.h>
#include<process.h>
#define ss 20
class string
{
char *p;
int size;
public:
struct range
{int i;
range(int s):i(s){};
};// конец класса range
string(int SIZE){p=new char[size=SIZE];}
~string(){delete[] p;}
char& operator[](int s);
};//конец класса string
char& string :: operator[](int s)
{if((s<0)||(s>size)) throw range(s);
return p[s];}
int main()
{
SetConsoleOutputCP(1251);
int index;
string str(ss);
for(int i=0;i<ss;i++) str[i]='A'+i;
try
{
for(;;) //бесконечный цикл
{cout<<"\nВведите индекс: ";
cin>>index;
cout<<str[index];}
}
catch(string ::range ob)
{cerr<<"Неверный индекс: "<<ob.i<<endl;
}
system("pause");
return 0;
}
Пример 5.2.2
В классе range задается переменная i с атрибутом private, получающая значение ошибочного индекса и две public функции get_index() и index_range(), которые соответственно возвращают значение ошибочного индекса и диапазон допустимых индексов.
class range
{int i;
int s;
public:
range(int I,int S):i(I),s(S){}
int get_index(){return i;}
void index_range(){cout<<"Допустимый диапазон:0 - "<<s<<endl;}
};
При ошибке создается объект range, содержащий уже два значения: ошибочный индекс и максимальное значение индекса.
char& string::operator[](int j)
{if((j<0)||(j>=size)) throw range(j,size); return p[j];}
Таким образом, поскольку исключение–это класс, он может содержать любые поля и методы.
5.3. Определение типа исключения
Во время выполнения программы в ней могут возникать различные ошибки, которые можно сопоставить с исключениями различных типов. Например, для класса string можно рассмотреть два типа возможных ошибок: неправильное значение индекса и невозможность конструирования объекта из-за того, что задан очень большой размер строки.
class string
{…
public:
class range{};
class error_size{};
string(int);
~string();
char& operator[](int);
};
Мы хотим использовать исключение для того, чтобы установить, правильно ли сконструирован объект. Мы знаем, что конструктор не возвращает никаких значений, поэтому нельзя использовать традиционные подходы для проверки правильности конструирования объекта. Но эту задачу можно решить другим способом.
string : : string(int s)
{if((s<0)||(s>max)) throw error_size();
p=new char[size=s];
}
или таким образом:
string : : string(int s)
{p=new char[size=s];
if(!p) throw error_size();
}
Тогда прикладная программа выглядит следующим образом:
void main()
{…
try
{
описание и выполнение каких-либо операций с объектами класса string
}
catch(string : : range){…}
catch(string : : error_size){…}
}
При наличии ошибки активизируется соответствующий обработчик исключений.
void f()
{…
try{…}
catch(string : : range)
{исправление ошибки и повторный вызов функции f();
}
catch(string : : error_size)
{выдача сообщений и завершение программы
exit(1);
}
}
Здесь записана часть функции, которая будет выполнена, если либо не было исключений, либо была достигнута закрывающая фигурная скобка исключения range. Функция f может перехватывать лишь некоторые исключения. Например, можно рассмотреть такие две функции f1 и f2, что f1 перехватывает только error_size, а f2 – только range. В этом случае после блока try первой функции записывается один блок catch(string : : error_size), а после блока try второй – один блок catch(string : : range).
Также можно в программе использовать два блока try, один из которых позволяет выявлять ошибки конструирования объекта, а второй – ошибки индекса.
