- •Тема 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. Гибридные базы данных
- •Рекомендуемая литература
Тема8.Производные классы (2 часа)
8.1. Определение производного класса
Вспомним определение наследования, тесно связанного с понятием производных классов.
Наследование- это механизм получения нового класса на основе уже существующего. Существующий класс может быть дополнен или изменен для создания нового класса.
Существующие классы называются базовыми, а новые –производными. Производный класс наследует описание базового класса; затем он может быть изменен добавлением новых членов, изменением существующих функций-членов и изменением прав доступа. Таким образом, наследование позволяет повторно использовать уже разработанный код, что повышает производительность программиста и уменьшает вероятность ошибок. С помощью наследования может быть создана иерархия классов, которые совместно используют код и интерфейсы.
При наследовании некоторые имена методов и данных базового класса могут быть по-новому определены в производном классе. В этом случае соответствующие компоненты базового класса становятся недоступными из производного класса. Для доступа к ним используется операция указания области видимости '::'.
В иерархии производный объект наследует разрешенные для наследования компоненты всех базовых объектов (public,protected).
Допускается множественное наследование – возможность для некоторого класса наследовать компоненты нескольких никак не связанных между собой базовых классов. В иерархии классов соглашенияотносительно доступности компонентов класса следующие:
private– Член класса может использоваться только функциями-членами данного класса и функциями-"друзьями" своего класса.В производном классе он недоступен.
protected – То же, что и private, но дополнительно член класса с данным атрибутом доступа может использоваться функциями-членами и функциями-"друзьями" классов, производных от данного. Ключевое слово protected (в переводе с английского - защищенный) введено для того, чтобы сохранить сокрытие данных для членов, которые должны быть доступны из производного класса, но в других случаях действуют как закрытые, т.е. private.
public– Член класса может использоваться любой функцией, которая является членом данного или производного класса, а также кpublic-членам возможен доступ извне через имя объекта.
Следует иметь в виду, что объявление friendне является атрибутом доступа и не наследуется.
Синтаксис определения производного класса:
class имя_класса : (public| protected| private) список_базовых_классов
{список_компонентов_класса};
8.2. Правила использования атрбутов доступа
Явно изменить умалчиваемый статус доступа при наследовании можно с помощью атрибутов доступа – private,protectedиpublic, которые указываются непосредственно перед именами базовых классов. Как изменяются при этом атрибуты доступа в производном классе показано в следующей таблице
атрибут, указанный при наследовании |
атрибут в базовом классе |
атрибут, полученный в производном классе |
public |
public protected private |
public protected недоступен |
protected |
public protected private |
protected protected недоступен |
private |
public protected private |
private private недоступен |
Таким образом, можно только сузить область доступа, но не расширить.
Итак, внутри производного класса существует четыре уровня, для которых определяется атрибут доступа:
для членов базового класса;
для членов производного класса;
для процесса наследования;
для изменения атрибутов при наследовании.
Рассмотрим, как при этом регулируется доступ к членам класса извне класса и внутри класса.
Доступ извне.
Доступными являются лишь элементы с атрибутом public.
Собственные члены класса.
Доступ регулируется только атрибутом доступа, указанным при описании класса.
Наследуемые члены класса.
Доступ определяется атрибутами доступа базового класса, ограничивается атрибутом доступа при наследовании и изменяется явным указанием атрибута доступа в производном классе.
Пример 8.1
class Basis
{
protected:
int b, c;
public:
int a;
};
class Derived : public Basis
{
public:
Basis::c;
};
int main (void)
{
Basis ob;
Derived od;
ob.a; // правильно
ob.b; // ошибка
od.c; // правильно
od.b; // ошибка
return 0;
}
Доступ изнутри.
Собственные члены класса.
private и protected члены класса могут быть использованы только функциями-членами данного класса.
Наследуемые члены класса.
private-члены класса могут использоваться только собственными функциями-членами базового класса, но не функциями членами производного класса.
protected или public члены класса доступны для всех функций-членов. Подразделение на public, protected и private относится при этом к описаниям, приведенным в базовом классе, независимо от формы наследования.
Пример 8.2
class Basis
{
public:
void f1(int i)
{
a = i;
b = i;
}
int b;
private:
int a;
};
class Derived : private Basis
{
public:
void f2(int i)
{
a = i; // ошибка
b = i; // правильно
}
};
Следующий пример познакомит нас более подробно с синтаксисом наследования в С++. В примере приведено описание базового класса (Base1), public-производного класса (PublicDerived1) и private-производного класса (PrivateDerived1). Для иллюстрации всех изменений в разграничении доступа эти классы имеют поля данных и функции-члены в каждой из закрытой, защищенной и открытой частях. Объекты (они же экземпляры класса) всех классов объявлены в функции main:
Пример 8.3
class Base1 //создание базового класса
{
private: //закрытые данные
int data1;
int function1();
protected: //защищенные данные
int data2;
int function2();
public: //открытые данные
int data3;
int function3();
};
class PublicDerived1:public Base1 //создание public-производного класса
{
private: //закрытые данные
int data4;
int function4();
protected: //защищенные данные
int data5;
int function5();
public: //открытые данные
int data6;
int function6();
};
class PrivateDerived1:private Base1 //создание private-производного класса
{
private: //закрытые данные
int data7;
int function7();
protected: //защищенные данные
int data8;
int function8();
public: //открытые данные
int data9;
int function9();
};
void main()
{
Base1 aBase1; //экземпляр базового класса
PublicDerived1 aPublicDerived1; //экземпляр public-производного класса
PrivateDerived1 aPrivateDerived1; //экземпляр private-производного класса
}
Разберем правила доступа к закрытым, защищенным и открытым частям классов Base1, PublicDerived1 и PrivateDerived1. Т.е. выясним, что к чему имеет доступ...
Доступ к протоколу класса. Обращаем Ваше внимание на то, что описание класса имеет доступ ко всем своим собственным частям. Вполне естественно, что любая функция-член в закрытой, защищенной или открытой частях описания класса имеет прямой доступ ко всем полям данных и всем функциям-членам описания своего класса. Таким образом, любая функция-член в классе Base1 имеет прямой доступ к data1, data2, data3, function1, function2 и function3. Аналогично, любая функция-член класса PublicDerived1 имеет прямой доступ к data4, data5, data6, function4, function5 и function6. Любая функция-член в классе Private-Derived имеет прямой доступ к data7, data8, data9, function7, function8, function8.
Доступ через протокол производного класса. Производные классы наследуют все протоколы (включая все поля данных и функции-члены) от своего базового класса. Однако, производный класс не имеет прямого доступа к полям данных или функциям-членам, определенным в закрытой части его базового класса. Классы PublicDerived1 и PrivateDerived1 наследуют data1 и function1 от своего базового класса (Base1), но не имеют прямого доступа к ним. Доступ можно обеспечить через функцию, определенную в защищенной или открытой частях класса Base1. Эта функция будет наследоваться открытыми и защищенными производными классами и будет доступна им.
Доступ через объекты класса. Объекты класса не имеют доступа к закрытой и защищенной частям описания класса. Они не могут получить прямой доступ к полям данных в закрытой и защищенной частях. Таким образом, объект aBase1 не имеет доступ к своим собственным закрытым элементам data1 и function1. Аналогично, объект aBase1 не имеет доступа к своим собственным защищенным элементам data2 и function2.
Доступ через объекты public-производного класса. Объекты public-производного класса не имеют доступа к закрытой и защищенной части базового класса. Если в классе Base1 определены открытые функции для доступа к закрытым или защищенным полям через объекты классов, то эти функции наследуются public-производными классами и могут использоваться объектами этих классов. Объекту aPublicDerived1 недоступны его собственные закрытые элементы data4 и function4.
Доступ через объекты private-производного класса. Объекты private-производного класса не имеют доступа к закрытой части их базового класса. Элементы data1 и function1 недоступны объекту aPrivateDerived1. Если в классе Base1 определены открытые функции для доступа к закрытым полям через объекты классов, то эти функции наследуются public-производными классами и могут использоваться объектами этих классов.