Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих (Стенли Липпман) 3-е хххх.pdf
Скачиваний:
86
Добавлен:
30.05.2015
Размер:
5.92 Mб
Скачать

С++ для начинающих

794

(d)const int hi = 40; const int wi = 80;

(e)const int size_val = 1024;

(f)unsigned int fasize = 255; Screen< hi, wi+32 > sObj;

Fixed_Array< string, size_val > fa1;

(g)const double db = 3.1415; Fixed_Array< int, fasize > fa2; Fixed_Array< double, db > fa3;

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

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

template <class Type> class Queue {

//...

public:

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

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

// ...

определения шаблона класса:

};

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

С++ для начинающих

795

template <class Type> class Queue { public:

Queue();

private: // ...

};

template <class Type> inline Queue<Type>::

Queue( ) { front = back = 0; }

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

Функция-член шаблона класса сама является шаблоном. Стандарт C++ требует, чтобы она конкретизировалась только при вызове либо при взятии ее адреса. (Некоторые более

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

Queue<string> qs;

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

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

16.3.1. Функции-члены шаблонов Queue и QueueItem

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

С++ для начинающих

796

template <class Type> class Queue { public:

Queue() : front( 0 ), back ( 0 ) { } ~Queue();

Type& remove();

void add( const Type & ); bool is_empty() const { return front == 0;

}

private:

QueueItem<Type> *front; QueueItem<Type> *back;

};

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

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

{

while (! is_empty() ) remove();

вне его. Деструктор Queue опустошает очередь:

}

template <class Type>

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

{

// создать новый объект QueueItem QueueItem<Type> *pt =

new QueueItem<Type>( val );

if ( is_empty() ) front = back = pt;

else

{

back->next = pt; back = pt;

}

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

}

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

С++ для начинающих

797

 

 

#include <iostream>

 

 

 

 

 

 

#include <cstdlib>

 

 

 

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, включив его

 

в каждый файл, где возможны конкретизации функций. (Обоснование этого решения, а

 

также рассмотрение более общих вопросов, касающихся модели компиляции шаблонов,

 

мы отложим до раздела 16.8.)

 

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

 

 

 

#include <iostream>

 

 

 

 

 

 

#include "Queue.h"

 

 

 

int main()

 

 

 

{

 

 

 

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

 

 

 

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

 

 

 

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

 

 

 

int ival;

 

 

 

for ( ival = 0; ival < 10; ++ival )

 

 

 

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

 

 

 

p_qi->add( ival );

 

 

 

int err_cnt = 0;

 

 

 

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

 

 

 

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

 

 

 

int qval = p_qi->remove();

 

 

 

if ( ival != qval ) err_cnt++;

 

 

 

}

 

 

 

if ( !err_cnt )

 

 

 

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

 

 

 

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

 

 

 

return 0;

 

шаблона Queue:

 

 

 

}

 

 

 

 

 

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