- •Тема 1.Понятие технологии программирования (2 часа). 3
- •Тема 2. Основные концепции ооп (2 часа). 7
- •Тема 3. Конструкторы и деструкторы (2 часа). 12
- •Тема 5. Дружественные функции (friend functions) (2 часа) 32
- •Тема 6. Обработка исключительных ситуаций (2 часа) 44
- •Тема 8. Производные классы (2 часа) 76
- •Тема 9. Виртуальные функции (2 часа) 83
- •Тема 10. Множественное наследование. Производные классы векторов (2 часа) 90
- •Тема 12. Шаблоны функций и классов. 128
- •Тема 14. Применение оо-подхода в базах данных 148
- •Тема 1.Понятие технологии программирования (2 часа).
- •1.1. Предмет изучения курса ооп
- •1.2. Исторический экскурс
- •1.3. Основные технологии программирования
- •1.4. Заключение
- •Тема 2. Основные концепции ооп (2 часа).
- •2.1. Объекты и классы
- •2.1.1.Понятие класса объектов
- •2.1.2. Основные характеристики состояния класса
- •2.1.3. Понятие инкапсуляции свойств объекта
- •2.1.4. Структура глобальной памяти класса и глобальные методы класса
- •2.1.5. Интерфейс класса
- •2.1.6. Функции-члены класса
- •2.2. Понятие наследования (Inheritance)
- •2.3. Понятиеполиморфизма
- •Тема 3. Конструкторы и деструкторы (2 часа).
- •3.1. Для чего нужны конструкторы
- •3.2. Использование конструкторов «по умолчанию»
- •3.3. Использование деструкторов
- •3.4. Демонстрация последовательности работы конструкторов и деструкторов
- •3.5. Конструктор копирования
- •3.6. Определение операции присваивания
- •3.6.1. Пример использования конструктора копирования.
- •3.7.1. Краткий обзор библиотеки stl
- •3.7.2. Вектора
- •3.8. Inline-подстановка
- •4.1. Перегрузка операторов
- •4.1.1. Пример на перегрузку операторов
- •4.1.2. Общие принципы перегрузки операторов
- •4.1.3. Бинарные и Унарные Операции
- •4.2. Пример с перегрузкой операторов
- •Тема 5. Дружественные функции (friend functions) (2 часа)
- •5.1. Примеры использования дружественных функций
- •5.2. Особенности перегрузки префиксной и постфиксной форм унарных операций
- •5.3. Статические члены данных
- •5.4. Перегрузка операторов new, new[], delete, delete[]
- •Void* operator new(size_t размер){ код оператора
- •Void operator delete(void* p){ код оператора }
- •Void* operator new[](size_t размер){ код оператора return указатель_на_память; }
- •Void operator delete[](void* p){ код оператора }
- •Тема 6.Обработка исключительных ситуаций(2 часа)
- •6.1. Применение try, catch, throw
- •6.2. Синтаксис и семантика генерации и обработки исключений
- •6.3. Обработка исключений
- •6.4. Обработка исключений при динамическом выделении памяти
- •6.5. Функции, глобальные переменные и классы поддержки механизма исключений
- •6.6. Конструкторы и деструкторы в исключениях
- •7.1 Строковые типы
- •7.1.1. Преобразования, определяемые классом
- •7.1.2. Встроенный строковый тип
- •7.1.3 Класс string
- •7.2. Пример строкового класса с перегруженными операторами и дружественными функциями
- •Тема8.Производные классы (2 часа)
- •8.1. Определение производного класса
- •8.2. Правила использования атрбутов доступа
- •8.3. Конструкторы и деструкторы производных классов
- •Тема 9. Виртуальные функции (2часа)
- •9.1. Определение виртуальных методов
- •9.2. Абстрактные классы
- •9.3. Таблицы виртуальных методов (функций)
- •9.4. Выводы
- •Тема 10. Множественное наследование. Производные классы векторов (2 часа)
- •10.1. Множественное наследование
- •10.2. Отношения между классами
- •10.2.3. Ассоциация
- •10.2.4. Агрегирование
- •10.2.5. Наследование
- •10.3. Библиотека графических объектов (пример)
- •10.3.1. Динамический полиморфизм и наследование интерфейсов
- •10.3.2.Абстрактные классы
- •10.3.3. Множественное наследование в библиотеке графичкских фигур.
- •10.3.4. Иерархия классов библиотеки графичкских фигур
- •10.3.5. Таблица наследования
- •10.3.6. Диаграмма модулей
- •10.3.7.Директивы препроцессора
- •10.4. Производные классы векторов
- •10.5. Операции над векторами
- •11.1. Потоковый ввод-вывод
- •11.1.1. Классы потоков
- •11.1.2. Стандартные потоки
- •11.2.Опрос и установка состояния потока
- •11.3.Перегрузка операций извлечения и вставки в поток
- •11.4.Переадресация ввода-вывода
- •11.5. Операции помещения в поток и извлечения из потока
- •11.6.Форматирование потока
- •11.7.Файловый ввод-вывод с использованием потоков
- •11.8.Бесформатный ввод-вывод
- •11.9.Часто применяемые функции библиотеки ввода / вывода
- •11.10.Файлы с произвольным доступом
- •11.11. Буферизация
- •11.12. Заключение
- •Тема 12. Шаблоны функций и классов.
- •12.1 Шаблоны функций
- •12.2. Шаблоны классов
- •12.3. Размещение определений шаблонов в многомодульных программах
- •12.4. Полиморфные вектора
- •13.1 Область видимости
- •13.1.1. Локальная область видимости
- •13.2. Глобальные объекты и функции
- •13.2.1. Объявления и определения
- •13.2.2. Несколько слов о заголовочных файлах
- •13.3. Локальные объекты
- •13.3.1. Автоматические объекты
- •13.3.2. Регистровые автоматические объекты
- •13.3.3. Статические локальные объекты
- •13.4. Динамически размещаемые объекты
- •13.4.1. Динамическое создание и уничтожение единичных объектов
- •13.5. Определения пространства имен а
- •Тема 14. Применение оо-подхода в базах данных
- •14.1. Реляционные базы данных
- •14.2 Объектно-ориентированные базы данных (ообд)
- •14.3. Гибридные базы данных
- •Рекомендуемая литература
6.3. Обработка исключений
Как уже было сказано, процедура обработки исключений определяется ключевым словом catch, вслед за которым в скобках помещена спецификация исключения, а затем в фигурных скобках следует блок обработки исключения. Эта процедура должна быть помещена непосредственно после контролируемого блока. Каждая процедура может обрабатывать только одно исключение заданного или преобразуюемого к заданному типа, который указан в спецификации ее параметра. Рассмотрим возможные преобразования при отождествлении исключения с процедурой обработки исключений. Стандартная схема:
try { /* Произвольный код, порождающий исключения X */ }
catch (Т х)
{ /* Некоторые действия, возможно с х */ }
Здесь определена процедура обработки для объекта типа T. Как уже говорилось, если исключениеXесть объект типаT,T&,const Tилиconst T&, то процедура соответствует этому объектуX. Кроме того, соответствие между исключениемXи процедурой обработки устанавливается в тех случаях, когдаTиXодного типа;T- доступный в точке порождения исключения базовый класс дляX;T- тип "указатель" иX- типа "указатель", причемXможно преобразовать к типуTпутем стандартных преобразований указателя в точке порождения исключения.
Просмотр процедур обработки исключений производится в соответствии с порядком их размещения в программе. Исключение обрабатывается некоторой процедурой в случае, если его тип совпадает или может быть преобразован к типу, обозначенному в спецификации исключения. При этом необходимо обратить внимание, что если один класс (например, ALPHA) является базовым для другого класса (например,BETA), то обработчик исключенияBETAдолжен размещаться раньше обработчикаALPHA, в противном случае обработчик исключения BETA не будет вызван никогда. Рассмотрим такую схему программы:
class ALPHA {};
class BETA : public ALPHA {};
...
void f1(void)
{
try
{ ... }
catch (BETA) // Правильно
{ ... }
catch (ALPHA)
{ ... }
}
void f2(void)
{
try
{ ... }
catch (ALPHA) // Всегда будет обработан и объект класса
{ ... // BETA, т.к. "захватываются" исключения
... // классов ALPHA к всех порожденных
} // от него
catch (BETA) // Неправильно: заход в обработчик
{ ... } // невозможен!
}
Если из контролируемого блока будет послано исключение типа BETA, то во втором случае, т.е. вf2(), оно всегда будет захвачено обработчикомALPHA, так какALPHAявляется доступным базовым классом дляBETA.
Заметим, что для явного выхода из процедуры обработки исключения или контролируемого блока можно также использовать оператор gotoдля передачи управления операторам, находящимся вне этой процедуры или вне контролируемого блока, однако операторомgotoнельзя воспользоваться для передачи управления обратно - в процедуру обработки исключений или в контролируемый блок.
После выполнения процедуры обработки программа продолжает выполнение с точки, расположенной после последней процедуры об работки исключений данного контролируемого блока. Другие процедуры обработки исключений для текущего исключения не выполняются.
try { // Тело контролируемого блока }
catch (спецификация исключения) { // Тело обработчика исключений }
catch (спецификация исключения) { // Тело обработчика исключений }
// После выполнения любого обработчика
// исполнение программы будет продолжено отсюда
Как уже показано выше, язык C++ позволяет описывать набор исключений, которые может порождать функция. Это описание исключений помещается в качестве суффикса в определении функции или в ее прототипе. Синтаксис такого описания исключений следующий:
throw (список идентификаторов типов)
где список идентификаторов типов- это один идентификатор типа или последовательность разделенных запятыми идентификаторов типов. Указанный суффикс, определяющий генерируемые функцией исключения, не входит в тип функции. Поэтому при описании указателей на функцию этот суффикс не используется. При описании указателя на функцию задают лишь возвращаемое функцией значение и типы аргументов.
Примеры прототипов функций с указанием генерируемых исключений:
void f2(void) throw(); // Функция, не порождающая
// исключении
void f3(void) throw(BETA); // Функция может порождать
// только исключение типа BETA
void (*fptr)(); // Указатель на функцию, возвращающую void
fptr = f2; // Корректное присваивание
fptr = f3; // Корректное присваивание
В следующих примерах описываются еще некоторые функции с перечислением исключений:
void f1(void); // Может порождать любые исключения
void f2(void) throw (); // Не порождает никаких исключений
void f3(void) throw (А, В*); // Может порождать исключения в виде
// объектов классов, порожденных из
// А или указателей на объекты
// классов, наследственно
// порожденных из В
Если функция порождает исключение, не указанное в списке, программа вызывает функцию unexpected(). Это происходит во время выполнения программы и не может быть выяснено на стадии ее компиляции. Поэтому необходимо внимательно описывать процедуры обработки тех исключений, которые порождаются функциями, вызываемыми изнутри (из тела рассматриваемой) функции.
Особое внимание необходимо обратить на перегрузку виртуальных функций тех классов, к которым относятся исключения. Речь идет о следующем. Пусть классы ALPHAиBETAопределены следующим образом:
class ALPHA // Базовый класс для BETA
{
public:
virtual void print(void)
{
cout " "print: Класс ALPHA";
}
};
class BETA : public ALPHA
{
public:
virtual void print(void)
{
cout << "print: Класс BETA";
}
};
BETA b; // Создан объект класса BETA
Теперь рассмотрим три ситуации:
try
{
throw(b); // Исключение в виде объекта класса BETA
}
catch (ALPHA d)
{
d.print ();
}
try
{
throw(b); // Исключение в виде объекта класса BETA
}
catch (ALPHA &d)
{
d.print ();
}
try
{
throw(b); // Исключение в виде объекта класса BETA
}
catch (BETA d)
{
d.print ();
}
В первом случае при входе в обработчик фактический параметр, соответствующий формальному параметру ALPHA d, воспринимается как объект типаALPHA, даже если исключение создано как объект классаBETA, Поэтому при обработке доступны только компоненты классаALPHA. Результатом выполнения этого фрагмента будет печать строки:
print: Класс ALPHA
Во втором случае во избежание потери информации использована передача значения по ссылке. В этом случае будет вызвана компонентная функция print()классаBETA, и результат будет таким:
print: Класс BETA
Попутно отметим, что функция print()класса BETA будет вызываться и в том случае, если она будет являться защищенным (protected) или собственным (private) компонентом классаBETA. Так, если в описании классаBETAвместо ключевого словаpublicпоставитьprotectedилиprivate, то результат не изменится. В этом нет ничего удивительного, так как права доступа к виртуальной функции определяются ее определением и не заменяются на права доступа к функциям, которые позднее переопределяют ее. Поэтому и в данном случае права доступа к функцииprintопределяются правами, заданными в классеALPHA.
Конечно, можно непосредственно "отлавливать" исключение в виде объекта класса BETA, как показано в третьем примере. Однако в этом случае если функцияprintо будет входить в число защищенных или собственных компонентов классаBETA, такой вызов функцииprint()окажется невозможным, и при компиляции будет выдано сообщение об ошибке.