57
Синтаксис шаблонов
Если вы собираетесь использовать шаблоны, привыкайте к тому, что в вашей речи будет часто звучать
термин параметризованный (parameterized). Шаблоны используются для создания параметризованных
типов (обычно классов) и параметризованных функций.
Параметризованные типы
Параметризованный тип внешне представляет собой обычное объявление класса, которому
предшествует магическое заклинание
template
, где
Type
— выбранное вами
символическое имя (остальные элементы задаются жестко). Всюду, где символическое имя
Type
(или
другое имя) встречается в объявлении класса оно интерпретируется как макрос, вместо которого при
использовании класса подставляется конкретный тип. Класс
ListNode
, переписанный как
параметризованный тип, выглядит следующим образом:
template
class ListNode {
private:
ListNode*
next;
Type*
data;
public:
ListNode(Type* d, ListNode* n = NULL) : next(n), data(d) {}
~ListNode() { delete next; }
Type* Data() { return data; }
ListNode* Next() { return next; }
};
ListNode list = new ListNode (new Foo);
Foo* f = list->Data();
// Возвращает правильный тип
В теле объявления класса формальный параметр шаблона резервирует место, на которое при
использовании класса подставляется фактический параметр. При этом компилятор буквально
генерирует правильный, безопасный по отношению к типам код.
Параметризованные функции
Параметризованные функции объявляются точно так же — перед их объявлениями указывается
формула
template...
. Синтаксис шаблона должен повторяться как при объявлении, так и при
определении функции. Помните, шаблоны на самом деле являются макросами, поэтому они должны
находиться в файлах .h. Если определение будет находиться в файле .срр, программа работать не будет
(если только это не единственный файл .срр, в котором вызывается данная функция).
// Объявление функции
template
Type* fn(Type* t);
// Определение ее реализации
template
Type* fn(Type* t) {
//
Тело функции, в котором имя Type
//
используется в качестве параметра макроса
}
Foo* f = fn(new Foo);
Определение генерируется компилятором при необходимости, то есть при вызове функции. На этот раз
параметризовано имя функции, а не имя класса.
58
Параметризованные функции классов
Параметризованные функции классов определяются так же (разве что вам понадобится больше
угловых скобок
<
и
>
). Давайте модифицируем класс
ListNode
так, чтобы его функции не
определялись при объявлении класса.
template
class ListNode {
private:
ListNode
next;
Type*
data;
public:
ListNode(Type* d, ListNode* n = NULL);
~ListNode();
Type*
Data();
ListNode*
Next();
};
template
ListNode::ListNode(Type* d, ListNode* n = NULL)
:
next(n),
data(d)
{
}
template
ListNode::~ListNode()
{
delete
next;
}
template
Type* ListNode::Data()
{
return
data;
}
template
ListNode* ListNode::Next()
{
return
next;
}
Помните: все это должно находиться в файле .h. Исключение составляют ситуации, когда функции
класса вызываются только из файла .срр, в котором они определяются. В этом случае определения
функций класса должны предшествовать их первому использованию.
Передача параметра
Многочисленные символы
<
и
>
вызывают изрядную путаницу, поскольку C++ не всегда
последователен. Вообще говоря,
<Туре>
следует указывать везде, кроме трех мест в объявлениях
классов или определениях их функций:
1. За ключевым словом
class
в самом начале.
2. При указании имени конструктора.
3. При указании имени деструктора.
Аргументы конструкторов и деструкторов должны быть параметризованными, как и все использования
имени класса за исключением трех указанных случаев. При любом использовании параметризованного
Do'stlaringiz bilan baham: |