C++ для начинающих - страница 21

стр.

Вот как может выглядеть шаблон класса Array:


>template class elemType

>class Array {

>public:

>explicit Array( int sz = DefaultArraySize );

>Array( const elemType *ar, int sz );

>Array( const Array iA );


>virtual ~Array() { delete[] _ia; }


>Array operator=( const Array );

>int size() const { return _size; }

>virtual elemType operator[]( int ix )

>{ return _ia[ix]; }


>virtual void sort( int,int );

>virtual int find( const elemType );

>virtual elemType min();

>virtual elemType max();

>protected:

>void init( const elemType*, int );

>void swap( int, int );

>static const int DefaultArraySize = 12;

>int _size;

>elemType *_ia;

>};


Ключевое слово template говорит о том, что задается шаблон, параметры которого заключаются в угловые скобки (). В нашем случае имеется лишь один параметр elemType; ключевое слово class перед его именем сообщает, что этот параметр представляет собой тип.

При конкретизации класса-шаблона Array параметр elemType заменяется на реальный тип при каждом использовании, как показано в примере:


>#include iostream

>#include "Array.h"


>int main()

>{

>const int array_size = 4;

>// elemType заменяется на int


>Arrayint ia(array_size);


>// elemType заменяется на double

>Arraydouble da(array_size);

>// elemType заменяется на char

>Arraychar ca(array_size);


>int ix;


>for ( ix = 0; ix array_size; ++ix ) {

>ia[ix] = ix;

>da[ix] = ix * 1.75;

>ca[ix] = ix + 'a';

>}

>for ( ix = 0; ix array_size; ++ix )


>ia[ix]

> "\tca: " ca[ix]

> "\tda: " da[ix] endl;

>return 0;

>}


Здесь определены три экземпляра класса Array:


>Arrayint ia(array_size);

>Arraydouble da(array_size);

>Arraychar ca(array_size);


Что делает компилятор, встретив такое объявление? Подставляет текст шаблона Array, заменяя параметр elemType на тот тип, который указан в каждом конкретном случае. Следовательно, объявления членов приобретают в первом случае такой вид:


>// Arrayint ia(array_size);

>int _size;

>int *_ia;


Заметим, что это в точности соответствует определению массива IntArray.

Для оставшихся двух случаев мы получим следующий код:


>// Arraydouble da(array_size);

>int _size;

>double *_ia;


>// Arraychar ca(array_size);

>int _size;

>char *_ia;


Что происходит с функциями-членами? В них тоже тип-параметр elemType заменяется на реальный тип, однако компилятор не конкретизирует те функции, которые не вызываются в каком-либо месте программы. (Подробнее об этом в разделе 16.8.)

При выполнении программа этого примера выдаст следующий результат:


>[ 0 ] ia: 0 ca: a da: 0

>[ 1 ] ia: 1 ca: b da: 1.75

>[ 2 ] ia: 2 ca: c da: 3.5

>[ 3 ] ia: 3 ca: d da: 5.25


Механизм шаблонов можно использовать и в наследуемых классах. Вот как выглядит определение шаблона класса ArrayRC:


>#include cassert

>#include "Array.h"


>template class elemType

>class ArrayRC : public ArrayelemType {

>public:

>ArrayRC( int sz = DefaultArraySize )

>: ArrayelemType( sz ) {}

>ArrayRC( const ArrayRC r )

>: ArrayelemType( r ) {}

>ArrayRC( const elemType *ar, int sz )

>: ArrayelemType( ar, sz ) {}

>elemType ArrayRCelemType::operator[]( int ix )

>{

>assert( ix = 0 ix ArrayelemType::_size );

>return _ia[ ix ];

>}

>private:

>// ...

>};


Подстановка реальных параметров вместо типа-параметра elemType происходит как в базовом, так и в производном классах. Определение


>ArrayRCint ia_rc(10);


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

>// функцию swap() тоже следует сделать шаблоном


>swap( ia1, 1, ia1.size() );


был допустимым, нам потребуется представить функцию swap() в виде шаблона.


>#include "Array.h"

>template class elemType

>inline void

>swap( ArrayelemType array, int i, int j )

>{

>elemType tmp = array[ i ];

>array[ i ] = array[ j ];

>array[ j ] = tmp;

>}


При каждом вызове swap() генерируется подходящая конкретизация, которая зависит от типа массива. Вот как выглядит программа, использующая шаблоны Array и ArrayRC:


>#include iostream

>#include "Array.h"

>#include "ArrayRC.h"

>template class elemType

>inline void

>swap( ArrayelemType array, int i, int j )

>{

>elemType tmp = array[ i ];

>array[ i ] = array[ j ];

>array[ j ] = tmp;

>}


>int main()

>{

>Arrayint ia1;

>ArrayRCint ia2;


>cout "swap() with Arrayint ia1" endl;