Шаблоны классов
Вы можете создавать шаблоны и для классов, что позволяет столь же красиво работать с любыми типами данных. Классическим примером являются контейнерные классы (т.е. классы, содержащие типы), например множества. Используя шаблон, можно создавать родовой класс для множеств, после чего порождать конкретные множества - цветов, строк и т.д.
Давайте сначала рассмотрим вполне тривиальный пример, просто чтобы привыкнуть к используемому синтаксису. Рассматриваемый далее пример - класс, который хранит пару значений. Принадлежащие функции этого класса передают минимальное и максимальное значения, а также позволяют определить, являются ли два значения одинаковыми. Еще раз повторю, что раз перед нами шаблон класса, то тип значения может быть почти любым.
template <class T>
class Pair
{
T a, b;
public:
Pair (T t1, T t2);
T Max();
T Min ();
int isEqual ();
};
Пока все выглядит также изящно, как и для шаблонов функций. Единственная разница состоит в том, что вместо описания функции используется объявление класса. Шаблоны классов становятся все более сложными, когда вы описываете принадлежащие функции класса. Вот, например, описание принадлежащей функции Min() класса Pair:
template <class T>
T Pair <T>::Min()
{
return a < b ? a : b;
}
Чтобы понять эту запись, давайте вернемся немного назад. Если бы Pair был обычным классом (а не шаблоном класса) и T был бы некоторым конкретным типом, то функция Min класса Pair была бы описана таким образом:
T Pair::Min()
{
return a < b ? a : b;
}
Для случая шаблонной версии нам необходимо, во-первых, добавить заголовок шаблона template <class T>
Затем нужно дать имя классу. Помните, что на самом деле мы описываем множество классов - семейство Pair. Повторяя синтаксис префикса (заголовка) шаблона, экземпляр класса Pair для целых типов, можно назвать Pair<int>, экземпляр для типа double - Pair<double>, для типа Vector - Pair<Vector>. Однако в описании принадлежащей функции нам необходимо использовать имя класса Pair<T>. Это имеет смысл, так как заголовок шаблона говорит, что Т означает имя любого типа.
Приведем текст остальных методов класса Pair. Описания методов помещаются в заголовочный файл, так как они должна быть видимы везде, где используется класс Pair.
// конструктор
template <class T>
Pair <T>::Pair (T t1, T t2) : a(t1), b(t2)
{}
// метод Max template <class T>
T Pair <T>::Max()
{
return a>b ? a : b;
}
// метод isEqual template <class T>
int Pair <T>::isEqual()
{
if (a==b) return 1;
return 0;
}
Ранее уже отмечалось, что шаблоны функций могут работать только для тех (встроенных) типов данных или классов, которые поддерживают необходимые операции. То же самое справедливо и для шаблонов классов. Чтобы создать экземпляр класса Pair для некоторого классового типа, например для класса X, этот класс должен содержать следующие общедоступные функции
X (X &); // конструктор копирования
int operator == (X)
int operator < (X);
Три указанные функции необходимы, так как они реализуют операции, выполняемые над объектами типа T в метода шаблона класса Pair.
Если вы собираетесь использовать некоторый шаблон класса, как узнать какие операции требуются? Если шаблон класса снабжен документацией, то эти требования должны быть в ней указаны. В противном случае придется читать первичную документацию - исходный текст шаблона. При этом учитывайте, что встроенные типы данных поддерживают все стандартные операции.