Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на C / C++ / C++ for real programmers.pdf
Скачиваний:
262
Добавлен:
02.05.2014
Размер:
2.04 Mб
Скачать

57

Синтаксис шаблонов

Если вы собираетесь использовать шаблоны, привыкайте к тому, что в вашей речи будет часто звучать термин параметризованный (parameterized). Шаблоны используются для создания параметризованных типов (обычно классов) и параметризованных функций.

Параметризованные типы

Параметризованный тип внешне представляет собой обычное объявление класса, которому предшествует магическое заклинание template <c1ass Type>, где Type — выбранное вами символическое имя (остальные элементы задаются жестко). Всюду, где символическое имя Type (или другое имя) встречается в объявлении класса оно интерпретируется как макрос, вместо которого при использовании класса подставляется конкретный тип. Класс ListNode, переписанный как параметризованный тип, выглядит следующим образом:

template <class Type> class ListNode { private:

ListNode<Type>* next; Type* data;

public:

ListNode(Type* d, ListNode<Type>* n = NULL) : next(n), data(d) {} ~ListNode() { delete next; }

Type* Data() { return data; } ListNode<Type>* Next() { return next; }

};

ListNode<Foo> list = new ListNode<Foo> (new Foo);

Foo* f = list->Data(); // Возвращает правильный тип

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

Параметризованные функции

Параметризованные функции объявляются точно так же — перед их объявлениями указывается формула template.... Синтаксис шаблона должен повторяться как при объявлении, так и при определении функции. Помните, шаблоны на самом деле являются макросами, поэтому они должны находиться в файлах .h. Если определение будет находиться в файле .срр, программа работать не будет (если только это не единственный файл .срр, в котором вызывается данная функция).

//Объявление функции template <class Type> Type* fn(Type* t);

//Определение ее реализации template <class Type>

Type* fn(Type* t) {

//Тело функции, в котором имя Type

//используется в качестве параметра макроса

}

Foo* f = fn<Foo>(new Foo);

Определение генерируется компилятором при необходимости, то есть при вызове функции. На этот раз параметризовано имя функции, а не имя класса.

58

Параметризованные функции классов

Параметризованные функции классов определяются так же (разве что вам понадобится больше угловых скобок < и >). Давайте модифицируем класс ListNode так, чтобы его функции не определялись при объявлении класса.

template <class Type> class ListNode { private:

ListNode<Type*> next; Type* data;

public:

ListNode(Type* d, ListNode<Type>* n = NULL); ~ListNode();

Type* Data(); ListNode<Type>* Next();

};

template <class Type>

ListNode<Type>::ListNode(Type* d, ListNode<Type>* n = NULL) : next(n), data(d)

{

}

template <class Type> ListNode<Type>::~ListNode()

{

delete next;

}

template <class Type>

Type* ListNode<Type>::Data()

{

return data;

}

template <class Type>

ListNode<Type>* ListNode<Type>::Next()

{

return next;

}

Помните: все это должно находиться в файле .h. Исключение составляют ситуации, когда функции класса вызываются только из файла .срр, в котором они определяются. В этом случае определения функций класса должны предшествовать их первому использованию.

Передача параметра

Многочисленные символы < и > вызывают изрядную путаницу, поскольку C++ не всегда последователен. Вообще говоря, <Туре> следует указывать везде, кроме трех мест в объявлениях классов или определениях их функций:

1. За ключевым словом class в самом начале.

2.При указании имени конструктора.

3.При указании имени деструктора.

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