5.1. Шаблоны
функций Часто встречаются функции,
реализующие одни и те же действия для аргументов
различных типов. Например, сортировка массива по
возрастанию его элементов может выполняться
одним и тем же методом и для данных типа int и для
данных типа double. Различие состоит только в типах
параметров и некоторых внутренних переменных.
В более поздние версии С++ включено специальное
средство, позволяющее параметризовать
определение функции, чтобы компилятор мог
построить конкретную реализацию функции для
указанного типа параметров функции.
Параметризованное определение функции строится
по схеме:
template < class имя_класса >
Заголовок функции
{ /* Тело функции */ }
Имя класса является параметром и задается
идентификатором, локализованным в пределах
определения функции. Хотя бы один из параметров
функции должен иметь тип, соответствующий этому
идентификатору.
Параметризованное определение функции
сортировки массива методом перестановок может
быть построено следующим образом:
template <class T >
void sort ( T a[ ], int n )
{ T temp;
int sign;
for ( int k = 0; k > n; k++)
{ sign = 0;
for ( i = 0; i <n - k; i++)
if ( a [ i ] > a [ i + 1])
{ temp = a [ i ];
a[ i
] = a[ i + 1 ];
a[ i
+ 1 ] = temp; sign++;
}
if ( sign == 0 ) break;
}
return;
}
Если в программе будут объявлены массивы
int aint [10];
double afl [20];
и установлены значения элементов этих
массивов, то вызов функции
sort ( aint, 10 );
обеспечит вызов sort для упорядочения массива
целых, а вызов функции
sort ( afl , 20 )
обеспечит вызов sort для упорядочения массива с
элементами типа double.
Если элементами массива являются объекты
какого-либо определенного программистом класса,
для которого определена операция отношения >,
то функция sort может быть вызвана и для такого
массива. Разумеется, в объектном коде программы
будут присутствовать все варианты реально
вызывамой функции sort. Параметризация функции
сокращает объем исходного текста программы и
повышает его надежность.
В описателе template можно указывать несколько
параметров вида class имя_типа, а также параметры
базовых типов. Например, функция
template < class T1, class T2 >
void copy ( T1 a[ ], T2 b[ ], int n)
{ for ( int i = 0; i <n; i++)
a[ i ] = b [ i ] ;
}
копирует первые n элементов массива b типа T2 в
первые n элементов массива a типа T1. Разумеется,
программист несет ответственность за то, чтобы
такое копирование было возможным.
5.2. Шаблоны классов
По аналогии с параметризованной функцией можно
построить параметризованное описание класса,
позволяющее создавать экземпляры классов для
конкретных значений параметров.
Параметризованный класс описывается следующим
образом:
template <class T >
class описание класса
Как и для функций, в описателе template может быть
задано несколько параметров. В самом описание
класса имена параметров используются как имена
типов данных, типов параметров функций и типов
значений, возвращаемых функциями.
В качестве примера приведем описание класса
stack, предназначенного для построения стеков
фиксированного максимального размера с
элементами произволного типа.
enum BOOLEAN ( FALSE, TRUE );
template <class Type >
class stack
{ private:
enum ( EMPTY = -1 );
Type* s; /*
Указатель на массив стека */
int max_len; /*
Максимальная длина стека */
int top; /*
Индекс элемента в вершине стека */
public:
stack ( ) : max_len ( 100 ) /* конструктор без
параметров */
{ s = new Type [ 100 ]; top = EMPTY; }
stack ( int size ) : max_len( size ) /* Второй
конструктор */
{ s = new Type [ size ]; top = EMPTY; }
~stack ( ) { delete [ ] s; } /*
Деструктор */
void reset ( ) { top = EMPTY; } /*
Очистить стек */
void push ( Type c ) { s [ ++top ] = c; }
Type pop ( ) { return (s [top—] }
Type top_of ( ) { return ( s [top ] }
BOOLEAN empty ( ) { return BOOLEAN ( top == EMPTY ) }
BOOLEAN full ( ) { return BOOLEAN ( top == max_len )
}
};
Следует отметить, что в этом примере с целью
сокращения исходного текста не предусмотрен
контроль выхода за пределы стека в методах push и
pop.
Чтобы создать экземпляр параметризованного
объектного типа, нужно уточнить имя типа
значением параметра в угловых скобках:
В приведенном примере все компоненты-функции
определены в описании класса. Когда полное
определение функции-члена класса задается вне
описания класса, оно должно уточняться
описателем template. Например, если бы метод top_of был
определен вне описания класса, определение имело
бы вид:
Отметим некоторые специфические черты
описаний параметризованных классов.
Если в параметризованном классе определены
friend-функции, то когда такая функция не зависит от
параметра, будет использоваться единственная
friend-функция для всех значений параметра, а когда
friend-функция зависит от параметра, будет
использоваться своя friend-функция для каждого
значения параметра.
Если в параметризованном классе имеются
статические (static) компоненты, то для каждого
значения параметра будет использоваться свой
экземпляр статической компоненты. |