Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOAP.doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
494.59 Кб
Скачать

4.4. Функции-члены шаблонов классов

Как и для обычных классов, функция-член шаблона класса может быть определена либо внутри определения шаблона (и тогда называется встроенной), либо вне его. Конструктор Queue является встроенным, так как определен внутри определения шаблона класса:

template < class Type>

class Queue {

// ...

public:

// встроенный конструктор

Queue(): front(0), last(0){ }

// ...

};

При определении функции-члена шаблона вне определения самого шаблона следует применять специальный синтаксис для обозначения того, членом какого именно шаблона является функция. Определению функции-члена должно предшествовать ключевое слово template, за которым следуют параметры шаблона. Так, конструктор Queue можно определить следующим образом:

template < class Type>

class Queue {

public:

Queue();

private:

// ...

};

template < class Type>

inline Queue< Type> ::

Queue( ) { front = last = 0; }

За первым вхождением Queue (перед оператором ::) следует список параметров, показывающий, какому шаблону принадлежит данная функция-член. Второе вхождение Queue в определение конструктора (после оператора ::) содержит имя функции-члена, за которым может следовать список параметров шаблона, хотя это и необязательно. После имени функции идет ее определение;. в нем могут быть ссылки на параметр шаблона Type всюду, где в определении обычной функции использовалось бы имя типа.

Функция-член шаблона класса сама является шаблоном. Стандарт C++ требует, чтобы она конкретизировалась только при вызове либо при взятии ее адреса. (Некоторые более старые компиляторы конкретизируют такие функции одновременно с конкретизацией самого шаблона класса.) При конкретизации функции-члена используется тип того объекта, для которого функция вызвана: Queue< string> qs;

Объект qs имеет тип Queue<string>. При инициализации объекта этого класса вызывается конструктор Queue<string>. В данном случае аргументом, которым конкретизируется функция-член (конструктор), будет string.

От того, в какой именно момент конкретизируется функция-член, зависит разрешение имен в ее определении и объявление ее специализации.

Чтобы понять, как определяются и используются функции-члены шаблонов классов, продолжим изучение шаблонов Queue и QueueItem:

template <class Type>

class Queue {

public:

Queue(): front(0), last(0) { }

~Queue();

Type& remove();

void add( const Type & );

bool empty() const {

return front == 0;

}

private:

QueueItem< Type> *front;

QueueItem< Type> *last;

};

Деструктор, а также функции-члены remove() и add() определены не в теле шаблона, а вне его. Деструктор Queue опустошает очередь:

template < class Type>

Queue< Type> ::~Queue()

{

while (! is_empty() )

remove();

}

Функция-член Queue< Type> ::add() помещает новый элемент в конец очереди:

template <class Type> void Queue< Type> ::add( const Type &val )

{

// создать новый объект QueueItem

QueueItem< Type> *pt = new QueueItem< Type>(val);

if ( is_empty() )

front = last = pt;

else

{

last-> next = pt;

last = pt;

}

}

Функция-член Queue<Type>:: remove() возвращает значение элемента, находящегося в начале очереди, и удаляет сам элемент.

#include < iostream>

#include < stвdlib>

template < class Type> Type Queue< Type> ::remove()

{

if (is_empty() )

{

cerr << "remove() вызвана для пустой очереди\n";

exit(1);

}

QueueItem< Type> *pt = front;

front = front-> next;

Type retval = pt->item;

delete pt;

return retval;

}

Поместим определения функций-членов в заголовочный файл Queue.h, включив его в каждый файл, где возможны конкретизации функций

В следующей программе иллюстрируется использование и конкретизация функции-члена шаблона Queue:

#include < iostream>

#include "Queue.h"

int main()

{

// конкретизируется класс Queue< int>

// оператор new требует, чтобы Queue< int> был определен

Queue< int> *p_qi = new Queue< int>;

int i;

for (i = 0; I < 10; ++i)

// конкретизируется функция-член add()

p_qi-> add(i);

int err_cnt = 0;

for(i = 0; i < 10; ++i) {

// конкретизируется функция-член remove()

int q = p_qi-> remove();

if (i != q) err_cnt++;

}

if (!err_cnt)

cout < < "!! queue executed ok\n";

else cerr << "?? queue errors: " < < err_cnt << endl;

return 0;

}

После компиляции и запуска программа выводит следующую строку:

!! queue executed ok.

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

Определение шаблона статического члена должно быть вынесено за пределы определения самого шаблона класса, которое начинается с ключевого слово template с последующим списком параметров. Определения таких членов помещаются в заголовочный файл Queue.h и должны включаться во все файлы, где производится их конкретизация. Статический член конкретизируется по шаблону только в том случае, когда реально используется в программе. Сам такой член тоже является шаблоном. Определение шаблона для него не приводит к выделению памяти: она выделяется только для конкретизированного экземпляра статического члена. Каждая подобная конкретизация соответствует конкретизации шаблона класса. Таким образом, обращение к экземпляру статического члена всегда производится через некоторый конкретизированный экземпляр класса.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]