Программирование на C и C++

Онлайн справочник программиста на C и C++

Классы-шаблоны

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

Классы-шаблоны полезны тогда, когда класс содержит логику, допускающую значительные обобщения. Например, алгоритм для обработки очереди целых чисел также будет работать с очередью символов. Аналогично механизм, поддерживающий связанный список почтовых адре­сов, также может поддерживать связанный список сведений об автомобилях. Используя классы- шаблоны, можно создавать классы, поддерживающие очереди, связанные списки и т. д. для про­извольных типов данных. Компилятор автоматически создаст корректный код, основываясь на типе данных, указанном перед компиляцией. Общая форма объявления класса-шаблона показа­на ниже:

template < class птип> class имя_класса {
...
}

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

После создания класса-шаблона можно создать конкретный экземпляр этого класса, используя следующую общую форму:

имя_класса <тип> объект;

Здесь тип является именем типа данных, с которыми будет оперировать данный класс.

Функции-члены класса-шаблона являются сами по себе автоматически шаблонами. Нет необхо­димости особым образом указывать на то, что они являются шаблонами с использованием ключе­вого слова template.

В следующей программе создается класс-шаблон stack, реализующий стандартный стек «послед­ним вошел — первым вышел». Он может использоваться для реализации стека с произвольным типом данных. В представленном здесь примере создаются стеки символов, целых чисел и чисел с плавающей точкой.

// демонстрация класса-шаблона stack
#include <iostream.h>
const int SIZE = 100;
// создание класса-шаблона stack
template <class SType> class stack {
SType stck[SIZE];
int tos;
public:
stack();
~stack();
void push(SType i);
SType pop();
};
// функция-конструктор stack
template <class SType> stack<SType>::stack()
{
tos = 0;
cout << "Stack Initialized\n";
}
/* функция-деструктор stack
This function is not required. It is included for illustration only. */
template <class SType> stack<SType>::~stack()
{
cout << "Stack Destroyed\n";
}
// помещение объекта в стек
template <class SType> void stack<SType>::push(SType i)
{
if (tos==SIZE) {
cout << "Stack is full. \n";
return;
}
stck[tos] = i;
tos++;
}
// извлечение объекта из стека
template <class SType> SType stack<SType>::pop()
{
if(tos==0) {
cout << "Stack underflow.\n";
return 0;
}
tos --;
return stck[tos];
}
int main()
{
stack<int> a; // создание целочисленного стека
stack<double> b; // создание вещественного стека
stack<char> с; //создание символьного стека
int i;
// использование целого и вещественного стеков
a.push (1);
b.push (99.3);
a.push(2);
b.push(-12.23);
cout << a.pop() << " ";
cout << a.pop() <<  " ";
cout << b.pop() << " ";
cout << b.pop() << "\n";
// демонстрация символьного стека
for (i=0; i<10; i++) с.push ( (char) 'A'+i);
for (i=0; i<10; i+ + ) cout << c.pop();
cout << "\n";
return 0;
}

Как можно видеть, объявление класса-шаблона подобно объявлению функции-шаблона. Тип-шаблон используется при объявлении класса и его функции-члена. При объявлении конкретного экземп­ляра класса stack компилятор автоматически генерирует все необходимые функции и данные, необходимые для обработки фактических данных. В этом примере объявляются три различных типа стеков (один для целых чисел, другой для вещественных и третий для символов). Рассмотрим следующее объявление:

stack<int> а; // создание целочисленного стека
stack<double> b; // создание вещественного стека
stack<char> с; // создание символьного стека

Обратим внимание, каким образом нужный тип данных подставляется в угловые скобки. Изме­няя тип данных, указываемый при создании объектов класса stack, одновременно изменяется тип данных, хранящихся в стеке. Например, можно создать другой стек, хранящий указатели на символы:

stack<char *> chrptrstck;

Также можно создать стек, содержащий определенный тип данных. Например, можно хра­нить адреса, используя структуру:

struct addr {
char name[40];
char street[40];
char city[30];
char state[3];
char zip[12];
}

Далее можно использовать класс stack для создания стека, в котором хранятся объекты типа addr:

stack<addr> obj;