Шаблоны классов: не только для типов
Параметризовать некоторый класс так, чтобы он работал для любого типа данных - это только половина того, что шаблоны обеспечивают для классов. Другой аспект состоит в том, чтобы дать возможность задания числовых параметров. Это позволяет Вам, например, создавать объекты типов "Вектор из 20 целых", "Вектор из 1000 целых" или "Вектор из 10 переменных типа double".
Основная идея проста, хотя используемый синтаксис может показаться сложным. Давайте в качестве примера рассмотрим некоторый обобщенный класс Vector. Как и класс Pair, класс Vector содержит функции Min(), Max(), isEqual(). Однако в нем может быть любое количество участников, а не два. В класс Pair число участников фиксировано и задаются они в качестве аргументов конструктора. В шаблоне Vector вместо этого используется второй параметр заголовка шаблона:
template <class T, int n> class Vector
{
public:
Vector();
~Vector() {delete[] coord;}
void newCoord (T x);
T Max ();
T Min();
int isEqual();
private:
T *coord;
int current;
};
Значение n, заданное в заголовке шаблона не используется в описании класса, но применяется в описании его методов. Конструктор Vector, использующий значение n для задания размера массива, выглядит так:
// конструктор
template <class T, int n>
Vector <T, n>::Vector():
{
coord = new T[n];
current = 0;
}
// метод Max
template <class T, int n>
T Vector <T, n>::Max():
{
T result (coord[0]); // *
for (int i=0; i<n; i++)
if (result < coord[i]) // **
result = coord[i]; // ***
}
В конструкторе задается список инициализаций, устанавливающих начальные значения для двух элементов класса. Элемент coord инициализируется адресом динамически размещенного массива размером n и состоящего из элементов типа Т, а элемент current инициализируется значением 0.
Опять, заметим, что в качестве Т может выступать почти любой тип. Однако и в этом случае успешная реализация возможна лишь при определенных условиях - для объектов, чей тип передается в шаблон в качестве параметра, должны быть определены следующие операции
1. конструктор копирования (*),
2. оператор < (**), и > для метода Max(),
3. оператор = (***).
Имеется несколько вариантов использования шаблонов с параметрами-значениями для динамического размещения массивов различных размеров. Например, можно передать размер массива конструктору. Указание размеров объекта во время конструирования или путем обращения к некоторому методу действительно обеспечивает задание размера, однако такой способ не позволяет создать отдельный тип для каждого отдельного размера. Подход с использованием шаблона гарантирует, что размер становится частью типа. Так, Vector вектор с пятью элементами типа double является типом, отличным от Vector с четырьмя элементами типа double.
Хотите ли Вы, чтобы различные размеры были различными типами, зависит от ваших нужд. Если сравнение двух векторов с четырьмя и пятью координатами не имеет особого смысла, то было бы неплохо сделать их различными типами. Вместе с тем, в случае классов для матриц, Вы, возможно, не захотите иметь особый тип для каждого размера матриц, так как, например, умножение, работает с матрицами различных размеров. Если Вы столкнетесь с подобной проблемой, то Вам потребуются только разумные проверки времени выполнения, а не контроль типов при компиляции.
Хотя числовые параметры шаблонов часто используются для задания размеров различных элементов, как это было показано для класса Vector, этим их применение не ограничивается. Например, с помощью числовых параметров можно задавать диапазоны значений графических координат в графическом классе.