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;
int size = ia1.size();
swap( ia1, 1, size );
cout "swap() with ArrayRCint ia2" endl;
size = ia2.size();
swap( ia2, 1, size );
return 0;
}
Упражнение 2.13
Пусть мы имеем следующие объявления типов:
templateclass elemType class Array;
enum Status { ... };
typedef string *Pstring;
Есть ли ошибки в приведенных ниже описаниях объектов?
(a) Array int* pri(1024);
(b) Array Arrayint aai(1024);
(c) Array complex double acd(1024);
(d) Array Status as(1024);
(e) Array Pstring aps(1024);
Упражнение 2.14
Перепишите следующее определение, сделав из него шаблон класса:
class example1 {
public:
example1 (double min, double max);
example1 (const double *array, int size);
double operator[] (int index);
bool operator== (const example1) const;
bool insert (const double*, int);
bool insert (double);
double min (double) const { return _min; };
double max (double) const { return _max; };
void min (double);
void max (double);
int count (double value) const;
private:
int size;
double *parray;
double _min;
double _max;
}
Упражнение 2.15
Имеется следующий шаблон класса:
template class elemType class Example2 {
public:
explicit Example2 (elemType val=0) : _val(val) {};
bool min(elemType value) { return _val value; }
void value(elemType new_val) { _val = new_val; }
void print (ostream os) { os _val; }
private:
elemType _val;
}
template class elemType
ostream operator(ostream os,const Example2elemType ex)
{ ex.print(os); return os; }
Какие действия вызывают следующие инструкции?
(a) Example2Arrayint* ex1;
(b) ex1.min (ex1);
(c) Example2int sa(1024),sb;
(d) sa = sb;
(e) Example2string exs("Walden");
(f) cout "exs: " exs endl;