- •Тема 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. Гибридные базы данных
- •Рекомендуемая литература
10.2. Отношения между классами
Между классами возможны следующие виды отношений:
Ассоциация
Агрегирование (с владением и без владения)
Наследование
Использование
10.2.3. Ассоциация
Смысловая связь.
Пример: сделки/товары, группы/студенты и т.д.
Типы: один к одному (сделка/проводка), один ко многим (группа/студент), многие ко многим (продавец/покупатель).
10.2.4. Агрегирование
Отношение вида “часть”. Когда один объект состоит из других объектов.
Примеры:
Агрегирование с владением: части автомобиля.
Агрегирование без владения: аэропорт и самолёты.
10.2.5. Наследование
Наследование – это такое отношение между классами, когда один класс повторяет структуру и поведение другого класса (одиночное наследование) или других (множественное наследование) классов.
Класс, поведение и структура которого наследуется называется базовым (родительским) классом, а класс, который наследует – производным или.
В производном классе структура и поведение базового класса дополняются и переопределяются. Производный класс является уточнением базового класса.
«Лакмусовая бумажка» наследования – обратная проверка; так, если В не есть А, то В не стоит производить от А.
В С++ наследование используется в двух целях:
Наследование интерфейсов
Наследование структуры и реализации класса
10.3. Библиотека графических объектов (пример)
Наследование должно использоваться только для выражения общности объектов. Когда выполняется правило «является». Нежелательно использовать наследование для компоновки объектов. Наследование есть классификация.
Запись наследования в C++:
Наследование в С++ |
class Shape { // … };
class Sphere : public Shape { // … }; |
В данном случае указывается, что класс Sphereнаследует классуShape. Наследование означает, что производный класс повторяет структуру базового класса и наследует все его методы.
Далее рассматривается пример конкретной иерархии классов.
Базовый класс Shape(фигура) содержит координаты фигуры и метод перемещения фигуры в заданную позицию. Также он содержит перегружен
ный конструктор, создающий фигуру в начале координат или в точке, указанной пользователем
Базовый класс – фигура |
class Shape { vec2d pos; public: Shape(); Shape(const vec2& aPos);
void MoveTo(const vec2d& newPos); };
Shape::Shape() : pos(0.0,0.0) {}
Shape::Shape(const vec2& aPos) : pos(aPos) {}
void Shape::MoveTo(const vec2d& newPos) { pos = newPos; } |
Класс Circle(окружность) наследует классуShape(фигура). Здесь выполняется правило «окружность является фигурой». Класс привносит новый член данныхradius– атрибут, специфичный для окружности и два метода –Draw(нарисовать фигуру) иErase(стереть фигуру).
Методы DrawиEraseне имеет смысла определять в классеShape, поскольку не известно, как нарисовать или стереть абстрактную фигуру.
Окружность |
|
class Circle : public Shape { double radius; public: Circle(double aRadius); Circle(double aRadius, const vec2d& aPos);
void Draw() const; void Erase() const; };
Circle::Circle(double aRadius) : radius(aRadius) {}
Circle::Circle(double aRadius, const vec2d& aPos) : Shape(aPos), radius(aRadius) {} |
Класс вводит собственный перегруженный конструктор, который позволит создавать объекты типа Circle.
При реализации конструктора, создающего окружность с заданным радиусом, инициализируется только член данных radius. Положение фигуры (окружности) в пространстве инициализируется по умолчанию конструктором классаShape. То есть до создания объектаCircleвначале автоматически создаётся унаследованная отShapeчасть и вызывается её конструктор.
В случае с конструктором, создающим окружность с заданным радиусом в заданных координатах, конструктор Shapeвызывается явно с передачей ему требуемого положения в пространстве. Из двух форм перегруженного конструктораShapeвызывается второй – размещающий фигуру в пространстве.
Пользователь может использовать созданный класс Circleследующим образом:
Использование класса Circle |
|
Circle cir1(20.0); cir1.MoveTo(vec2(200.0,200.0)); cir1.Draw(); cir1.Erase();
Circle cir2(20.0,vec2(100.0,100.0)); cir2.Draw(); cir2.Erase(); |
Класс Square(квадрат) также наследует фигуре:
Прямоугольник |
class Rectangle : public Shape { double orientation; double high, width; public: Rectangle(double aHigh, double aWidth); Rectangle(double aHigh, double aWidth, const vec2& pos, double aOrientation=0.0);
void Draw() const; void Erase() const;
void Rotate(double newOrientation); void SetHigh(double newHigh); void SetWidth(double newHigh); };
|
Часто при проектировании допускается типовая ошибка:
Квадрат |
class Square : public Rectangle { public: Square (double aSide); Square (double aSide, const vec2&pos, double aRotation=0.0);
void SetSide(double newSize); }; |
Кажется, что в данном классе всё хорошо, но из-за нарушения основного принципа при наследовании («объект наследуемого класса является объектом базового класса») создаётся неправильная иерархия. Дело в том, что квадрат только в математическом смысле является прямоугольником. Но он не является таковым с точки зрения обязательств. То есть квадрат не является фигурой, для которой возможно независимое изменение размеров сторон. А поэтому в рассматриваемой иерархии классов он не является прямоугольником.
Ошибка наследования видна сразу: классу Squareизбыточно хранить и высоту и ширину. Но главное, что интерфейс класса, добавив методSetSideнеобходимый для установления длинны стороны квадрата, не может скрыть от пользователя методыSetHighиSetWidth, унаследованные от классаRectangle.
Использование класса Square, приводящее к ошибке |
Square Square1(10.0); Square1.SetHigh(20.0); |
После выполнения второй строки размеры сторон квадрата окажутся разными, что приведёт к неправильной работе класса.
В рассматриваемой иерархии классов класс Squareправильнее наследовать классуShape.
Рассмотренное семейство классов фигур демонстрирует возможность использования наследования для достижения повторного использования кода. Единожды реализованное понятие фигуры (координаты, перемещение и т.д.) реализуется в производных классах. Каждому из производных классов нет необходимости определять соответствующие члены данных и методы. Всё это реализовано в базовом классе. В случае, если будет необходимо добавить новый функционал (например, управление цветом фигур), он может быть добавлен в базовый класс и производные классы воспользуются готовым решением без переработки собственной функциональности (или с минимальными изменениями).