Для знакомства с шаблонами классов перепишем наш простой стек (см. листинг 6.9), который верой и правдой послужил нам в главе 8 (см. листинги 8.9-8.12), превратив его в шаблон (листинг 11.1).
Листинг 11.1. Реализация стека в виде шаблона
#include <exception> // необходимо для исключений
#include <string> #include <iostream> using namespace std;
// класс-шаблон
template <class T> // шаблон; T - параметр шаблона
// тип элементов неизвестен // тип элементов - параметр шаблона
class TStack { struct Elem { T data; Elem *next;
Elem (const T& d. Elem *p) :data(d), next(p) { }
// указатель на вершину
// счетчик элементов
// закрыли копирование
// закрыли присваивание
};
Elem * Head; int count;
TStack(const TStack &); TStack& operator=(const TStack &) public:
class Error: public std::exception // искпючение - пустой стек { };
TStackO: Head(0), count(0) { }
-TStackO
{ while(!empty()) pop(); } void push(const T& d) { Head = new Elem(d. Head); ++count;
}
T top() const
// конструктор без аргументов
// деструктор!
// тип элементов - параметр шаблона
// новый элемент в стек
// увеличиваем счетчик
// тип возвращаемого элемента - параметр
{ if (lemptyO) return Head->data; else throw Error();
}
void pop() // удапение эпемента с вершины
{ if (emptyO) throw Error();
T top = Head->data; // T - параметр шаблона
Elem *oldHead = Head; Head = Head->next; delete oldHead;
--count; // уменьшаем счетчик
}
bool emptyO const // есть ли элементы в стеке
{ return Head==0; }
int countO const // количество элементов в стеке
{ return count; }
Листинг 11.1 (продолжение)
// программа-клиент, использующая шаблон стека
int main()
{ // стек с числами
TStack<double> t; // стек с числами типа double
t.push(ll); // помещаем в стек числа
t.push(21); t.push(31);
cout << t.count() << endl; //в стеке должно быть 3 элемента
while (!t.emptyO) // пока стек не пустой
{ cout << t.topO << endl; // выводим число с вершины
double р = t.popO; // удаляем элемент из стека
}
cout << t.count() << endl; // в стеке должно быть 0 элементов
// стек со строками
TStack<string> S; // стек со строками
S.push("one"); // помещаем в стек строки
S.push("two");
S.push("three");
cout << S.countO << endl;
while (!S.emptyO) // пока стек не пустой
{ string р = S.popO; // удаляем элемент из стека
cout << р << endl; // выводим строку
}
cout << S.countO << endl; // в стеке не должно быть элементов
try { string р = S.popO; } /'/ проверка исключения
catch(const exception &е) { cout << e.whatO << endl; } return 0;
}
Как можно видеть, шаблон класса начинается ключевым словом template. В угловых скобках после него записан параметр шаблона в виде <class Т>. Имя Т является параметром-типом. В качестве имени параметра можно использовать, конечно, любой допустимый идентификатор, однако по негласному соглашению в качестве имен параметров-типов указываются имена, начинающиеся с префикса Т. Внутри класса такой параметр может появляться на тех местах, где разрешается писать конкретный тип. В данном случае тип Т использовался, чтобы задать тип поля data в структуре Elem, как тип параметра в методе pushQ и как тип возвращаемого значения в методах top() и рор(). Сам шаблонный класс имеет тип TStack<T>. |