
- •5.Препроцессор. Директивы препроцессора.
- •7.Работа с файлами. Текстовый и двоичный режим.
- •8.Указатели. Адресная арифметика.
- •10.Перечислимый тип. Структуры. Объединения.
- •11.Поразрядные операции.
- •13.Спецификаторы класса памяти.
- •14.Пространства имён.
- •15.Компоновка. Правило одного определения.
- •16.Понятие класса.
- •17.Функции-члены класса. Указатель this.
- •18.Конструкторы. Деструкторы.
- •19.Преобразования объектов класса.
- •20.Доступ к членам класса.
- •21.Статические члены класса.
- •22.Друзья класса.
- •23.Совместное использование.
- •24.Перегрузка операций.
- •25.Шаблоны.
- •26.Обработка исключительных ситуаций.
- •27.Производные классы.
- •28.Виртуальные функции. Абстрактные классы.
- •29.Указатели на члены класса.
- •30.Множественное наследование.
- •31.Структура dll-библиотеки.
- •32.Статическое и динамическое подключение dll-библиотек.
- •34.Регистры процессора.
- •35.Использование стека. Команды работы со стеком в языке ассемблера.
- •36.Арифметические команды в языке ассемблера.
- •37.Команды сравнения и перехода в языке ассемблера.
- •38.Команды работы с битами в языке ассемблера.
- •39.Процедуры в языке ассемблера. Передача параметров в процедуру.
- •40.Процедуры в языке ассемблера. Возврат результата. Локальные данные.
25.Шаблоны.
Шаблоны обеспечивают простой способ введения разного рода общих концепций и простые методы их совместного использования. Получающиеся в результате классы и функции сопоставимы по времени выполнения и требованиям к памяти с написанным вручную специализированным кодом.
Шаблоны обеспечивают непосредственную поддержку обобщенного программирования, т.е. программирования с использованием типов в качестве параметров. Механизм шаблонов в C++ допускает использование типа в качестве параметра при определении класса или функции. Шаблон зависит только от тех свойств параметра-типа, которые он явно использует, и не требует, чтобы различные типы, используемые в качестве параметров, были связаны каким-либо другим образом. В частности, типы параметров шаблона не должны принадлежать к одной иерархии наследования.
Шаблон класса определяет данные и операции потенциально неограниченного множества родственных классов. Шаблон функции определяет потенциально неограниченное множество родственных (совместно используемых) функций.
Объявление шаблона имеет следующий синтаксис:template <список параметров шаблона> объявление
Здесь угловые скобки являются элементом синтаксиса.Объявление в объявлении шаблона должно описывать функцию или класс. Объявление шаблона может быть только глобальным.Список параметров шаблона не может быть пуст. Шаблон с пустым списком параметров может быть просто описан как обычный класс либо функции, и потому не имеет смысла.Процесс генерации объявления класса по шаблону класса и параметру шаблона часто называютинстанцированием шаблона. Аналогично, функция генерируется («инстанцируется») из шаблона функции и параметра шаблона. Версия шаблона для конкретного параметра называется специализацией. Сгенерированные классы являются совершенно обычными классами, которые подчиняются всем стандартным правилам для классов (например, у них могут быть дружественные функции). Аналогично, сгенерированные функции являются обычными функциями, которые подчиняются всем стандартным правилам для функций.
Шаблоны обеспечивают эффективный способ генерации кода из сравнительно коротких определений. Поэтому требуется некоторая осмотрительность во избежание заполнения памяти почти идентичными определениями функций.
Шаблоны функцийШаблон функции задаёт способ построения отдельных функций. Синтаксис шаблона функции:
template <список параметров шаблона функции> тип_функции имя_функции (список формальных параметров) { ... }
Все параметры из списка параметров шаблона функции должны быть так называемыми ти́повыми параметрами, т.е. параметрами, задающими типы формальных параметров функции и/или возвращаемого функцией значения.
template <typename TYPE> TYPE abs(TYPE x) { return x >= 0 ? x : -x; } void main() { int i = 567; double d = -123.45; printf("%7d\n", abs<int>(i)); printf("%7.2lf\n", abs<double>(d)); printf("%7d\n", abs(i)); printf("%7.2lf\n", abs(d)); } |
// Параметр шаблона определяется по типу фактического параметра функции // Параметр шаблона определяется по типу фактического параметра функции |
Тип, используемый в качестве параметра шаблона, должен обеспечивать интерфейс, ожидаемый шаблоном. Если мы попытаемся подставить в шаблон функции abs имя типа, для которого не определены операции >= и –, это приведет к ошибке.При отождествлении некоторого вызова функции с шаблоном функции генерируется отдельная шаблонная функция с параметрами, точно отождествляемыми с типами фактических параметров вызова.
template <typename TYPE> TYPE max(TYPE a, TYPE b) { return a > b ? a : b; } void main() { int i = 567; float f = 7.5; double d = -123.45; printf("%7d\n", max(i, 0)); printf("%7.2lf\n", max(d, 0)); printf("%7.2lf\n", max(d, 0.0)); printf("%7.2lf\n", max(d, f)); printf("%7.2lf\n", max(d, (double)f)); } |
// Всё правильно // Ошибка – 0 является константой целого типа // Всё правильно // Ошибка – f и d имеют разные типы // Всё правильно |
Шаблонная функция может совместно использоваться с другими (обычными) функциями и с другими шаблонными функциями. template <typename TYPE> TYPE max(TYPE a, TYPE b)
{ return a > b ? a : b; }
template <typename TYPE> TYPE max(TYPE a, TYPE b, TYPE c)
{ TYPE d; d = a;
if (b > d) d = b;
if (c > d) d = c;
return d; }
Шаблоны класса Шаблон класса задаёт способ построения отдельных классов. Синтаксис шаблона класса: template <список параметров шаблона класса> class имя_шаблона_класса { ... };Здесь угловые скобки являются элементом синтаксиса.
Имя шаблона класса должно быть уникально в программе. Список параметров шаблона класса может содержать ти́повые параметры, а также обычные параметры.После объявления шаблона можно объявить некоторый класс по этому шаблону: имя_шаблона_класса <список фактических параметров шаблона> Это объявление задаёт так называемое имя класса по шаблону. Каждый фактический параметр шаблона может быть именем пользовательского или стандартного типа (ти́повый параметр), шаблоном или выражением, а именно: константным выражением или адресом глобального объекта или функции или статического члена класса. template <class TYPE> class Vector
{ private:
int size;
TYPE *v;
public:
Vector(int n = 0);
~Vector(); ... };
template <class TYPE, int NMAX = 100> class Vector
{ private:
int size;
TYPE v[NMAX];
public:
Vector();
~Vector(); ... };
template <class CLASS, void (*err_fun)()> class List
{ ... };
Шаблоны функций-членов классаФункция-член шаблонного класса неявно оказывается шаблонной функцией, параметрами шаблона которой являются параметры шаблона класса. template <class TYPE, int NMAX> class Vector
{ private:
int size;
TYPE v[NMAX];
public:
Vector();
Vector(TYPE x); };
Данное объявление класса объявляет два шаблона функций. Соответственно их описание должно выглядеть следующим образом: template <class TYPE, int NMAX> Vector<TYPE, NMAX>::Vector()
{ size = NMAX;
for (int i = 0; i < size; i++)
v[i] = 0; }
template <class TYPE, int NMAX> Vector<TYPE, NMAX>::Vector(TYPE x)
{ size = NMAX;
for (int i = 0; i < size; i++)
v[i] = x; }
Дружественные функции Функция-друг шаблона не становится неявно шаблонной функцией. Однако если параметры функции или возвращаемое значение принадлежат шаблонному классу, такая функция становится шаблонной. template <class T> class X
{ public:
friend void f1();
friend X<T>* f2();
friend int f3(X<T> *p);
friend void f4(X *p); }; // Ошибка, т.к. не существует класса X
void f1() { ... }
template <class T> X<T>* f2 () { ... }
template <class T> int f3(X<T> *p) { ... }
Инстанцирование Процесс генерации объявления класса по шаблону класса и параметру шаблона часто называют инстанцированием шаблона. Аналогично, функция генерируется («инстанцируется») из шаблона функции и параметра шаблона. Версия шаблона для конкретного параметра называется специализацией.
Параметры шаблонов по умолчанию Шаблоны классов позволяют задавать значения по умолчанию для параметров шаблона. template <class TYPE = int, int NMAX = 10> class Vector
{ private:
int size;
TYPE v[NMAX]; ... };
Vector<> v;
Проверка семантики аргумента по умолчанию для параметра шаблона осуществляется тогда и только тогда, когда аргумент по умолчанию действительно используется.
Специализация По умолчанию, шаблон предоставляет единственное определение, которое должно использоваться для всех параметров шаблона или комбинаций параметров шаблона. Это не всегда имеет смысл для разработчика шаблона. Например, могут потребоваться разные реализации для параметров шаблона, являющихся указателями, и параметров, не являющихся указателями. Подобные проблемы можно решить, обеспечив альтернативные определения шаблона и предоставив компилятору делать выбор нужного варианта на основе параметров шаблона, указанных при его использовании. Такие альтернативные определения шаблона называются пользовательскими специализациями.
Например, можно определить отдельную функцию abs для параметра шаблона типа char, задав явное описание функции для этого типа. template <> char abs<char>(char x)
{ return x; }
Использование параметров шаблона для выбора алгоритма При разработке общих алгоритмов, например, сортировки или сравнения сложных объектов, таких как строка или вектор, критерий сравнения элементов объекта должен указывается при выполнении конкретной операции. Поэтому любое общее решение нуждается в том, чтобы алгоритмы были выражены в общих терминах, которые могут быть определены не только для какого-то конкретного типа. Организация исходного кода Существует два очевидных способа организации кода с использованием шаблонов:
включать определения шаблонов до их использования в единице компиляции;
включать только объявления шаблонов до их использования в единице компиляции, и компилировать их определения отдельно.
Первый вариант плох тем, что всё, от чего зависит определение шаблона, добавляется в каждый файл, использующий этот шаблон. Стратегия раздельной компиляции (второй вариант) является логическим завершением следующий мысли: если определение шаблона не включено в код пользователя, ни одна из его зависимостей не должна влиять на этот код.
Обратите внимание: для того чтобы к нему можно было обращаться из различных единиц компиляции, определение шаблона должно быть явно объявлено с ключевым словом export, которое означает «доступно из другой единицы компиляции». Это можно сделать, добавив export к определению или объявлению шаблона.*В противном случае определение должно находиться в области видимости в момент использования шаблона.