Содержание
10 Лекция. Обобщённое программирование. Шаблоны. Шаблонная функция. Шаблонный класс. Шаблоны: Array, List. DoubleList.
Обобщённое программирование — (англ. generic programming) — такое описании данных и алгоритмов, которое можно применять к различным типам данных, не меняя само это описание.
- Агентно-ориентированная
- Компонентно-ориентированная
- Конкатенативная
- Декларативная (контрастирует с Императивной)
- Ограничениями
- Функциональная
- Потоком данных
- Таблично-ориентированная (электронные таблицы)
- Реактивная
- Сервис-ориентированная
- Процедурная
- Автоматизация процесса программирования
- Обобщённое программирование
- Рефлексивно-ориентированная
- Итерационная
- Модульная
- Рекурсивная
- Объектно-ориентированная
- Автоматная
- Разделение ответственности:
- Аспектно-ориентированная
- Субъектно-ориентированная
Метапрограммирование — создание программ, которые порождают другие программы как результат своей работы, либо программ, которые меняют себя во время выполнения.
Все функции и классы, которые были приводились на лекциях, работали только с одним типом данных (чаще int).
Шаблоны. Шаблонная функция.
В языке C++ обобщённое программирование основывается на понятии «шаблон», обозначаемом ключевым словом template.
int max(int x, int y) // только для int if (x y) return y; else return x; >
template typename T> // шаблонная функция T max(T x, T y) if (x y) return y; else return x; >
Применение шаблонной функции..
1 2 3 4 5 6 7 8 9 10 11 12
int a = max(10,15); double f = max(123.11, 123.12); max(10,15); max(123.11, 123.12); maxint>(10,15); max double >(123.11, 123.12);
Шаблонный класс. Шаблоны: Array, List. DoubleList.
Перепишем все классы на шаблоны.
Шаблон Array.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// заголовочный файл для Array #ifndef ARRAY_H_ // проверка - не включался ли уже этот файл #define ARRAY_H_ // объявление константы typedef unsigned int size_t; // объявляем новый тип переменных size_t template typename T> // Объявляем шаблонный класс class Array // объявляем массив private: // модификатор доступа private size_t mySize; // поле - размер массива T *myData; // поле - указатель на массив public: // модификатор доступа public Array(size_t size); // прототип конструктора ~Array(); // прототип деструктора T set (int i, T val); // прототип метода записи элемента в массив, i- индекс val-значение T get (int i); // прототип метода запроса элемента, i- индекс size_t getSize(); // прототип метода получения размера массива Array(Array &a); // прототип метода конструктора копий Array& operator=(Array &a); // прототип метода переопределение оператора и копирования массива >; #endif // конец условия
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
// Реализации методов класса Array #include "array.h" template typename T> ArrayT>::Array(size_t size) // Реализация метода - конструктор mySize = size; // присвоение размера массива полю класса myData = new T [mySize]; // выделение памяти для массива в динамической памяти (куче) > template typename T> ArrayT>::~Array() // Реализация метода - деструктор delete myData; // освобождение памяти выделенной для массива > template typename T> void ArrayT>::set(int i, T val) // Реализация метода записи элемента в массив if(i0 || i>(mySize)) // Проверка выхода за рамки массива return -1; > myData[i]=val; // Запись элемента в массив > template typename T> T ArrayT>::get(int i) // Реализация метода запроса элемента массива if(i0 || i>(mySize)) // Проверка выхода за рамки массива return -1; > return myData[i]; // Запрос элемента массива > template typename T> size_t ArrayT>::getSize() // Реализация метода получения размера массива return mySize; // Возвращаем значение поля размера массива > template typename T> ArrayT>::Array(Array &a) // Реализация метода конструктора копий mySize = a.mySize; // Копируем значение поля размера массива myData = new T[mySize]; // Выделяем память в куче для нового массива for(int i=0;imySize;i++) // Перебираем элементы массива myData[i]=a.myData[i]; // Копируем элементы массива > > template typename T> ArrayT>& ArrayT>::operator=(Array &a) // Реализация метода присваивания if(this!=&a) // Проверяем, чтобы не присвоить массив сам в себя, this указатель на текущий объект в памяти mySize = a.mySize; // Копируем значение поля размера массива delete myData; // Освобождаем память от старого массива myData = new T [mySize]; // Выделяем память в куче для нового массива for(int i=0;imySize;i++) // Перебираем элементы массива myData[i]=a.myData[i]; // Копируем элементы массива > > return *this; // Возвращаем указатель на новый объект >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
// Основная программа работы с классом Array #include #include "array.cpp" int main () Arrayint> a(100); a.set(13,2345); std::cout<"Размер массива a color: #339933;">
getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; Arrayint> b(a); std::cout<"Размер массива b color: #339933;">getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; Arrayint> c(200); std::cout<"Размер массива c color: #339933;">getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; c=b; std::cout<"Размер массива c color: #339933;">getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; Arrayfloat> fa(100); fa.set(13,23.45); std::cout<"Размер массива a color: #339933;">getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; Arrayfloat> fb(fa); std::cout<"Размер массива b color: #339933;">getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; Arrayfloat> fc(200); std::cout<"Размер массива c color: #339933;">getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; fc=fb; std::cout<"Размер массива c color: #339933;">getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; Arraychar> ca(100); ca.set(13,'H'); std::cout<"Размер массива a color: #339933;">getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; Arraychar> cb(ca); std::cout<"Размер массива b color: #339933;">getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; Arraychar> cc(200); std::cout<"Размер массива c color: #339933;">getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; cc=cb; std::cout<"Размер массива c color: #339933;">getSize ()<"\n"; std::cout<"Элемент массива [13] color: #339933;">get (13)<"\n\n"; >Шаблон List.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
// изменения в классе односвязный список List, чтобы его можно было наследовать template class T> class List // объявление класса //private: // модификатор доступа private protected: // модификатор доступа protected, только наследникам, иначе методы наследники не смогут обратиться к полям T myValue; // поле значение List *myNext; // рекурсия, тип поля List, указатель на экземпляр класса public: // модификатор доступа public List(T value) // конструктор myValue=value; //инициализация поля myValue myNext=0; // инициализация поля myNext > ~List() // деструктор if(myNext!=0) // если не дошли до головы списка delete myNext; // освободить буфер в куче > > // метод нужно будет переписать, поэтому разрешить перекрытие этой функции(virtual) virtual void addValue(T value) // метод добавления элемента в список List *current=this; // сохраняем указатель на текущий экземпляр класса в *current while(current->myNext!=0) // идем к голове current=current->myNext; // берем следующий указатель > current->myNext=new List(value); // создаем новый экземпляр класса в куче и записываем указатель на него в поле myNext > int length() // метод получения длины списка int counter=0; // инициализация счетчика for(List *current=this;current!=0;current=current->myNext) // перебираем все элементы списка counter++; // увеличиваем счетчик > return counter; // возвращаем значение счетчика > // метод нужно будет переписать, поэтому разрешить перекрытие этой функции(virtual) virtual void Show() // метод вывода списка на консоль for(List *current=this;current!=0;current=current->myNext) // перебираем все элементы списка std::cout
- >myValue<"->"; // выводим значение элемента > std::cout<"0\n"; // выводим голову списка > >;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
// Основная программа работы с классом DoubleList #include #include "list.cpp" int main() Listint> L(5); std::cout<"Длина списка "
length ()<"\n"; L.Show(); L.addValue(6); std::cout<"Длина списка "length ()<"\n"; L.Show(); L.addValue(7); std::cout<"Длина списка "length ()<"\n\n"; L.Show(); Listchar> CL('H'); std::cout<"Длина списка "length ()<"\n"; CL.Show(); CL.addValue('K'); std::cout<"Длина списка "length ()<"\n"; CL.Show(); CL.addValue('F'); std::cout<"Длина списка "length ()<"\n"; CL.Show(); >Шаблон DoubleList.