Определение, описание и инстанцирование шаблонов



Мы поможем в написании ваших работ!


Мы поможем в написании ваших работ!



Мы поможем в написании ваших работ!


ЗНАЕТЕ ЛИ ВЫ?

Определение, описание и инстанцирование шаблонов



Шаблон классов (или шаблонный класс) определяет неограниченное семейство сходных классов. Определив такой шаблон лишь один раз, мы можем автоматически получать (инстанцировать) различные классы на его основе и формировать объекты этих классов[17]. Причем формироваться будут только те классы, которые реально нужны в программе.

В общем виде шаблон классов определяется в следующем формате:

template <template_parameter_list> template_class_declaration

где template_parameter_list – список параметров шаблона; template_class_declaration – определение самого шаблонного класса. Список параметров шаблона не может быть пустым и обязательно указывается в угловых скобках, причем отдельные параметры в нем перечисляются через запятые. Определение шаблонного класса выполняется практически так же, как и определение обычного класса.

Важнейшим элементом формата шаблона классов является список параметров шаблона. Он представляет те свойства объединяемых шаблоном классов, которыми эти классы отличаются друг от друга. Например, для шаблона, представляющего матрицы, в список параметров попадет тип элементов матрицы. При инстанцировании шаблона вместо параметров подставляются аргументы, которые конкретизируют обобщенные свойства. Так, в шаблон матриц можно передать аргумент int, выделив тем самым класс матриц с целочисленными элементами. Описание каждого параметра шаблона может начинаться одним из служебных слов class, typename или template, либо именем некоторого типа (стандартного или определенного пользователем). Последующее определение шаблонного класса использует имена из списка параметров шаблона, или, как говорят, является параметризованным. Более подробно о параметрах и аргументах шаблонов мы поговорим позднее, а сейчас рассмотрим несложный пример.

В качестве примера ниже приводится определение шаблонного класса CVector, моделирующего свойства векторов с элементами произвольного типа[18].

template <class item_t> class CVector {

item_t * __data; // данные вектора

int __size; // длина вектора

public:

Explicit CVector(int); // конструктор

~CVector() { delete[] data; } // деструктор

item_t & Item(int i) { // получение i–го элемента

return data[i];

}

...

};

В примере класс CVector параметризуется типом элементов вектора item_t. Этот обобщенный тип используется для определения массива элементов и возвращаемого значения в функции Item. Это, в свою очередь, дает возможность представления векторов с любым типом элементов.

Шаблон классов можно как определять, так и описывать, т.е. для него существует понятие предварительного объявления. При этом и описание, и определение шаблона могут размещаться только на уровне пространства имен или класса; в блоке или функции локализовать шаблон классов нельзя. Компонентные функции шаблона могут определяться как внутри него (см. деструктор ~CVector и функцию Item), так и за его пределами, т.е. могут иметь внешнее определение (конструктор CVector). Внешнее определение компонент при этом также должно быть параметризовано.

Ниже показано, как в общем виде дается внешнее определение компонентной функции шаблонного класса:

template <template_parameter_list>

value_type template_class_id<template_argument_list>

::function_id(function_parameter_list) { statements }

Здесь через template_argument_list обозначен список аргументов шаблона (аргументами могут быть, например, имена параметров шаблона); template_class_id<template_argument_list> называют полным идентификатором шаблонного класса[19]. Оставшаяся часть – это обычное внешнее определение компонентной функции function_id со списком параметров function_parameter_list, использующее параметры шаблона (value_type – тип возвращаемого функцией значения).

Ниже приведено внешнее определение конструктора шаблона CVector, введенного ранее.

template <class item_t> СVector<item_t>::СVector(int n)

{

if (n < 0) throw std::range_error(“invalid size”);

// при отрицательном размере генерируем исключение

// выделение памяти под элементы вектора

__data = new item_t[n];

// обнуление элементов

for (int i = 0; i < n; i++) __data[i] = static_cast<item_t>(0);

// фиксация размера вектора

__size = n;

}

Из заголовка конструктора видно, что он параметризован типом элемента вектора item_t, полное имя конструктора СVector<item_t>::СVector включает идентификатор шаблона СVector<item_t>, собственный параметр конструктора int n задает длину вектора. В теле конструктора используется обобщенный тип item_t.

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

template <template_parameter_list>

type template_class_id<template_argument_list>

::static_member_id = initializer;

где type – это тип статического компонента (он может каким-то образом зависеть от параметров шаблона); static_member_id – имя статического компонента; initializer – инициализирующее выражение.

Шаблонный класс в качестве компонента может содержать вложенные классы. Их определение и использование незначительно отличается от случая с обычными классами. Так, например, во внешнем определении вложенного в шаблон класса необходимо указание квалифицированного имени класса с полным идентификатором шаблона. Это также касается и внешнего определения компонент вложенного класса.

Ниже дан пример шаблонного класса, включающего статический компонент и вложенный класс:

Пример

// определение шаблонного класса

template <class T> struct X {

static T s;

class Y;

};

// определение статического компонента

template<class T> T X<T>::s = static_cast<T>(0);

// определение вложенного класса

template<class T> class X<T>::Y { /* ... */ };

Когда шаблон определен, от него можно формировать конкретные классы, а затем и объекты этих классов. Получить (инстанцировать) класс из шаблона можно путем указания конкретных аргументов шаблона; сформировать от этого класса объект можно по обычной схеме, принятой для классов, т.е. через вызов одного из конструкторов. Формат вызова конструктора для формирования объекта object_id шаблонного класса template_class_id выглядит так:

template_class_id <template_argument_list> object_id(arguments);

При обработке такого вызова компилятором выполняются два действия. Во-первых, от шаблона template_class_id неявно инстанцируется класс с идентификатором template_class_id<template_argument_list>, т.е. формируется его определение (в этом определении все обобщенные типы заменяются конкретными типами, переданными через аргументы). Во-вторых, формируется код вызова конструктора полученного класса для создания объекта object_id. Например:

CVector <double> Z(10);

В примере инстанцируется класс CVector<double>, от которого порождается объект Z – вектор из десяти вещественных компонент.

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

CVector <double> * pdVector;

Наряду с неявным инстанцированием шаблонных классов возможно их явное инстанцирование. Явное инстанцирование позволяет получить класс от шаблона путем задания конкретных аргументов. Записывается оно в следующем виде:

template <template_parameter_list>

template_class_id<template_argument_list>;

Такую форму инстанцирования разумно применять тогда, когда точно известно, что потребуется класс template_class_id <template_argument_list>.



Последнее изменение этой страницы: 2016-08-14; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.238.117.56 (0.005 с.)