- •Тема 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. Гибридные базы данных
- •Рекомендуемая литература
12.2. Шаблоны классов
Шаблоны классов также называют "генераторами классов" или "обобщенными классами". Они позволяют определять структуру семейства классов, по которой компилятор создаст классы в дальнейшем, основываясь на типах используемых данных.
Итак, мы с Вами выяснили, что в С++ существует возможность определить обобщенный класс. Это значит, что Вы можете создать класс, который определяет все используемые в нем алгоритмы, но реальный тип обрабатываемых данных будет задан как параметр при создании объектов этого класса. Другими словами, когда Вам необходимо разработать класс, который имеет одинаковую логику работы с разными типами данных (например, класс МАССИВ котрый одинаково работал бы как c данными типа int так и с double, Вашими собстенными типами данных), то лучше всего воспользоваться механизмом шаблонов.
Вот как выглядит общая форма объявления параметризованного (обобщенного) класса.
template <class Tтип_данных> class имя_класса {
//....описание класса.......
};
Рассомотрим это объявление. Здесь Tтип_данных представляет собой имя типа шаблона, которое в каждом случае конкретезации будет замещаться фактическим типом данных. При необходимости, можно определить более одного параметризовнного типа данных, используя список с разделителем-запятой, т.е. параметризованные классы могут иметь несколько аргументов шаблона. Заметим, что в пределах определения класса имя Tтип_данных можно использовать в любом месте. Когда создан параметризованный класс, Вы можете создать конкретную реализацию этого класса, используя следующий синтаксис:
имя_класса <тип_данных> объект;
В приведенном синтаксисе тип_данных представляет собою имя типа данных, над которыми фактически оперирует класс, и заменяет собой переменную Tтип_данных
Обращаем Ваше внимание также на тот факт, что функции-члены обобщенного класса автоматически являются обобщенными. Таким образом, их необязательно декларировать как параметризованные с помощью ключевого слова template, если Вы пишите реализацию этих функций внутри класса.
Вот как может выглядеть шаблон класса Array:
template <class elemType>
class Array {
protected: static const int DefaultArraySize = 12; int _size; elemType *_ia;
void init( const elemType*, int ); void swap( int, int );
public:
explicit Array( int sz = DefaultArraySize );
Array(const elemType *ar, int sz );
Array(const Array &iA );
virtual ~Array() { delete[] _ia; }
Array& operator=(const Array &); int size() const { return _size; }
virtual elemType& operator[]( int ix ) { return _ia[ix]; }
virtual void sort( int,int ); virtual int find( const elemType& ); virtual elemType min(); virtual elemType max(); };
Ключевое слово template говорит о том, что задается шаблон, параметры которого заключаются в угловые скобки (<>). В нашем случае имеется лишь один параметр elemType; ключевое слово class перед его именем сообщает, что этот параметр представляет собой тип. При конкретизации класса-шаблона Array параметр elemType заменяется на реальный тип при каждом использовании, как показано в примере:
#include <iostream>
#include "Array.h"
int main() { const int array_size = 4;
// elemType заменяется на int
Array<int> ia(array_size);
// elemType заменяется на double Array<double> da(array_size);
// elemType заменяется на char Array<char> ca(array_size);
int ix;
for ( ix = 0; ix < array_size; ++ix ) { ia[ix] = ix; da[ix] = ix * 1.75; ca[ix] = ix + 'a'; }
for ( ix = 0; ix < array_size; ++ix ) cout << "[ " << ix << " ] ia: " <<
ia[ix] << "\tca: " << ca[ix] << "\tda: " << da[ix] << endl;
return 0; }
Здесь определены три экземпляра класса Array:
Array<int> ia(array_size);
Array<double> da(array_size);
Array<char> ca(array_size);
Что делает компилятор, встретив такое объявление? Подставляет текст шаблона Array, заменяя параметр elemType на тот тип, который указан в каждом конкретном случае. Следовательно, объявления членов приобретают в первом случае такой вид:
// Array<int> ia(array_size);
int _size;
int *_ia;
Заметим, что это в точности соответствует определению массива IntArray. Для оставшихся двух случаев мы получим следующий код:
// Array<double> da(array_size);
int _size;
double *_ia;
// Array<char> ca(array_size); int _size; char *_ia;
Что происходит с функциями-членами? В них тоже тип-параметр elemType заменяется на реальный тип, однако компилятор не конкретизирует те функции, которые не вызываются в каком-либо месте программы.
Отметим, также, следующее особенности работы с парметризованными классами. Обобщенные классы могут содержать "друзей". Причем, если дружественная функция не использует спецификацию шаблона, то она универсальна - имеется единственный ее экземпляр для всех случаев параметризованного класса. Дружественная функция, которая использует аргументы шаблона, специфична для каждого варианта класса, то есть для разных вариантов класса, создаются разные варианты дружественной функции.
Согласно Страуструпу [1], использование шаблонов не подразумевает обязательного уменьшения сгенерированного кода. Хорошей идеей является тестирование конкретного класса до преобразования его в шаблон. Таким образом решаются проблемы проектирования и обнаруживается большая часть ошибок кода.
В заключении, еще раз напомним, что обобщенные классы полезно использовать в тех случаях, когда класс содержит обобщенную логику. Проще говоря, используя обобщенный класс, можно создать класс, который будет управлять стеком и т.д. для любого типа данных. Компилятор автоматическисгенерирует корректный код объекта на основе типа, задаваемого при создании этого объекта.
Наиболее показательный пример в данном случае - это создание семейства "вмещающих" классов, например, векторов.
#include <iostream.h>
template <class T>
class Vector
{
T *elements; //Указатель на массив элементов пока еще не известного типа
int size; //Максимальное число элементов
public:
Vector(int);
~Vector()
delete elements;
T& operator[](int i)
return elements[i];
void print_contents();
;
// Определение функций членов !!!!
template <class T>
Vector<T>::Vector(int)
elements=new T[n];
for(int i=0; i<n; elements[i]=(T)0,i++);
size=n;
;
template <class T>
void Vector<T>::print_contents()
cout<<"size="size<<"elements are:";
for(int i=0; i<size; i++);
cout<<' '<<elements[i];
cout<<'\n';
;
main()
//Создание векторов с элементами типа int, double и char,
//вмещающих по 10 элементов
Vector<int>i(10);
Vector<double>x(10);
Vector<char>ch(10);
//Присвоить элементам значения
for(int count=0; count<10; count++)
i[count]=count;
x[count]=0.1+count;
ch[count]='a'+count;
//Распечатать содержимое векторов
i.print_contents();
x.print_contents();
ch.print_contents();
И в этом случае применение template избавляет от лишней работы и делает программу изящной и компактной.
Некоторые замечания:
1) Шаблон может иметь более одного аргумента, и аргументом не обязательно должен быть класс:
template<class T, int size>
второй аргумент шаблона, size - это целое число, используемое непосредственно внутри класса.
2) Правило использования наследования вместе с шаблонами - те же, что и для обычных классов, за исключением того, что шаблон должен быть полностью специфирован.