Информатика и технология программирования

         

Шаблоны


Достаточно часто встречаются классы, объекты которых должны содержать элементы данных произвольного типа (в том смысле, что их тип определяется отдельно для каждого конкретного объекта). В качестве примера можно привести любую структуру данных (массив указателей, массив, список, дерево). Для этого в Си++ предлагаются средства, позволяющие определить некоторое множество идентичных классов с параметризованным типом внутренних элементов. Они представляют собой особого вида заготовку класса (ШАБЛОН), в которой в виде параметра задан тип (класс) входящих в него внутренних элементов данных. При создании конкретного объекта необходимо дополнительно указать и конкретный тип внутренних элементов в качестве фактического параметра. Создание объекта сопровождается созданием соответствующего конкретного класса для типа, заданного в виде параметра. Принятый в Си++ способ определения множества классов с параметризованным внутренним типом данных (иначе, макроопределение) называется шаблоном ( template ).

Синтаксис шаблона рассмотрим на примере шаблона класса векторов, содержащих динамический массив указателей на переменные заданного типа.


//------------------------------------------------------bk73-11.cpp


// &#60class T&#62 - параметр шаблона - класс "T", внутренний тип данных


// vector - имя группы шаблонных классов


template &#60class T&#62 class vector
{
int tsize; // Общее количество элементов


int csize; // Текущее количество элементов


T **obj; // Массив указателей на параметризованные объекты


public: // типа "T"




T *operator[](int); // оператор [int] возвращает указатель на


// параметризованный объект класса "T"


void insert(T*); // включение указателя на объект типа "T"


int index(T*); //


};

Данный шаблон может использоваться для порождения объектов-векторов, каждый из которых хранит объекты определенного типа. Имя класса при этом составляется из имени шаблона " vector" и имени типа данных (класса), который подставляется вместо параметра "Т":



vector&#60int&#62 a;
vector&#60double&#62 b;
extern class time;
vector&#60time&#62 c;



Заметим, что транслятором при определении каждого вектора с новым типом объектов генерируется описание нового класса по заданному шаблону (естественно, неявно в процессе трансляции). Например, для типа int транслятор получит:

class vector&#60int&#62
{
int tsize;
int csize;
int **obj;
public:
int *operator[](int);
void insert(int*);
int index(int*);
};



Далее следует очевидное утверждение, что функции- элементы шаблона также должны быть параметризованы, то есть генерироваться для каждого нового типа данных. Действительно, это так: функции-элементы шаблона классов в свою очередь также являются шаблонными функциями с тем же самым параметром. То же самое касается переопределяемых операторов:



//------------------------------------------------------bk73-12.cpp

// параметр шаблона - класс "T", внутренний тип данных

// имя функции-элемента или оператора - параметризовано

//

template &#60class T&#62 T* vector&#60T&#62::operator[](int n)
{
if (n &#62=tsize) return(NULL);
return (obj[n]);
}
template &#60class T&#62 int vector&#60T&#62::index(T *pobj)
{
int n;
for (n=0; n&#60tsize; n++)
if (pobj == obj[n]) return(n);
return(-1);
}

Заметим, что транслятором при определении каждого вектора с новым типом объектов генерируется набор элементов- функций по заданным шаблонам (естественно, неявно в процессе трансляции). При этом сами шаблонные функции должны размещаться в том же заголовочном файле, где размещается определение шаблона самого класса. Для типа int сгенерированные транслятором функции-элементы будут выглядеть так:



int* vector&#60int&#62::operator[](int n)
{
if (n &#62=tsize) return(NULL);
return (obj[n]);
}
int vector&#60int&#62::index(int *pobj)
{
int n;
for (n=0; n&#60tsize; n++)
if (pobj == obj[n]) return(n);
return(-1);
}

Шаблоны могут иметь также и параметры-константы, которые используются для статического определения размерностей внутренних структур данных.


Кроме того, шаблон может использоваться для размещения не только указателей на параметризованные объекты, но и самих объектов. В качестве примера рассмотрим шаблон для построения циклической очереди ограниченного размера для параметризованных объектов:



//------------------------------------------------------bk73-13.cpp

//-------Шаблон с параметром-константой

template &#60class T,int size&#62 class FIFO
{
int fst,lst; // Индексы начала и конца очереди

T queue[size]; // Массив объектов класса "T" размерности "size"

public:
T from(); // Функции включения-исключения

void into(T); //

FIFO(); // Конструктор

};

template &#60class T,int size&#62 FIFO&#60T,size&#62::FIFO()
{ fst = lst = 0; }

template &#60class T,int size&#62 T FIFO&#60T,size&#62::from()
{
T work;
if (fst !=lst)
{
work = queue[lst++];
lst = lst % size;
}
return(work);
}

template &#60class T,int size&#62 void FIFO&#60T,size&#62::into(T obj)
{
queue[fst++] = obj;
fst = fst % size;
}

Пример определения объектов шаблонного класса:



struct x {};
FIFO&#60double,100&#62 a;
FIFO&#60int,20&#62 b;
FIFO&#60x,50&#62 c;


Содержание раздела