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;