Шаблоны классов: не только для типов

Параметризировать некоторый класс так, чтобы он работал для любого типа данных - это только половина того, что шаблоны обеспечивают для классов. Другой аспект состоит в том, чтобы дать возможность задания числовых параметров. Это позволяет Вам, например, создавать объекты типов "Вектор из 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, этим их применение не ограничивается. Например, с помощью числовых параметров можно задавать диапазоны значений графических координат в графическом классе.

Наследование в шаблонах классов

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

Рассмотрим очень простой пример, на котором продемонстрируем, каким образом можно создать шаблон класса, производный из нашего шаблона класса Pair. Пусть это будет класс Trio, в котором к паре элементов a и b из Pair, добавим элемент c.

template <class T>

class Trio: public Pair <T>

{ T c;

public:

Trio (T t1, T t2, T t3);

...

};

template <class T>

Trio<T>::Trio (T t1, T t2, T t3): Pair <T> (t1, t2), c(t3)

{}

// Заметим, что вызов родительского конструктора

// также сопровождается передачей типа Т в качестве параметра.

Контрольные вопросы

1. Что такое шаблоны и с какой целью они используются?

2. Какого типа шаблоны используются в программах?

3. Как оформляются шаблоны функций?

4. Какие требования предъявляются к фактическим параметрам шаблонов?

5. Какие преимущества программы обеспечиваются при использовании шаблонов классов?

6. В чем смысл использования шаблонов?

7. Каковы синтаксис/семантика шаблонов функций?

8. Каковы синтаксис/семантика шаблонов классов?

9. Напишите параметризованную функцию сортировки массива методом обмена.

10. Определите шаблон класса “вектор” − одномерный массив.

11. Что такое параметры шаблона функции?

12. Перечислите основные свойства параметров шаблона функции.

13. Как записывать параметр шаблона?

14. Можно ли перегружать параметризованные функции?

15. Перечислите основные свойства параметризованных классов.

16. Может ли быть пустым список параметров шаблона? Объясните.

17. Как вызвать параметризованную функцию без параметров?

18. Все ли компонентные функции параметризованного класса являются параметризованными?

19. Являются ли дружественные функции, описанные в параметризованном классе, параметризованными?

20. Могут ли шаблоны классов содержать виртуальные компонентные функции?

21. Как определяются компонентные функции параметризованных классов вне определения шаблона класса?

22. Какие классы и функции называются дружественными?

23. Как осуществляется перегрузка операций?

24. Сколько аргументов требуется для определения перегруженной унарной (бинарной) операции?

25. Чем отличается действие перегруженной операции ++ при ее использовании в префиксной форме от использовании в постфиксной форме?

Лабораторное задание

В каждом варианте первой задачи необходимо реализовать функции заполнения, вывода элементов.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: