Использование шаблонов
Наш класс IntArray служит хорошей альтернативой встроенному массиву целых чисел. Но в жизни могут потребоваться массивы для самых разных типов данных. Можно предположить, что единственным отличием массива элементов типа double от нашего является тип данных в объявлениях, весь остальной код совпадает буквально.
Для решения данной проблемы в С++ введен механизм шаблонов. В объявлениях классов и функций допускается использование параметризованных типов. Типы-параметры заменяются в процессе компиляции настоящими типами, встроенными или определенными пользователем. Мы можем создать шаблон класса Array, заменив в классе IntArray тип элементов int на обобщенный тип-параметр. Позже мы конкретизируем типы-параметры, подставляя вместо них реальные типы int, double и string. В результате появится способ использовать эти конкретизации так, как будто мы на самом деле определили три разных класса для этих трех типов данных.
Вот как может выглядеть шаблон класса 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
а Array<int> ia(array_size);
а // elemType чрьхэ хЄё эр double
а Array<double> da(array_size);
а // elemType чрьхэ хЄё эр char
а Array<char> 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 )
ааааааааа cout << "[ " << ix << " ]а ia: "а << ia[ix]
ааааааааааааа << "\tca: " << ca[ix]
ааааааааааааа << "\tda: " << da[ix] << endl;
а return 0;
}
¦фхё№ юяЁхфхыхэv ЄЁш ¤ъчхьяы Ёр ъырёёр Array:
Array<int> ia(array_size);
Array<double> da(array_size);
Array<char> ca(array_size);
+Єю фхырхЄ ъюьяшы ЄюЁ, тёЄЁхЄшт Єръюх юс· тыхэшх? ¦юфёЄрты хЄ ЄхъёЄ °рсыюэр Array, чрьхэ ярЁрьхЄЁ elemType эр ЄюЄ Єшя, ъюЄюЁvщ єърчрэ т ърцфюь ъюэъЁхЄэюь ёыєўрх. TыхфютрЄхы№эю, юс· тыхэш ўыхэют яЁшюсЁхЄр¦Є т яхЁтюь ёыєўрх Єръющ тшф:
// Array<int> ia(array_size);
int _size;
int *_ia;
¦рьхЄшь, ўЄю ¤Єю т ЄюўэюёЄш ёююЄтхЄёЄтєхЄ юяЁхфхыхэш¦ ьрёёштр IntArray.
-ы юёЄрт°шїё фтєї ёыєўрхт ьv яюыєўшь ёыхфє¦•шщ ъюф:
// Array<double> da(array_size);
intаааа _size;
double *_ia;
// Array<char> ca(array_size);
intаа _size;
char *_ia;
+Єю яЁюшёїюфшЄ ё ЇєэъЎш ьш-ўыхэрьш? T эшї Єюцх Єшя-ярЁрьхЄЁ elemType чрьхэ хЄё эр Ёхры№эvщ Єшя, юфэръю ъюьяшы ЄюЁ эх ъюэъЁхЄшчшЁєхЄ Єх ЇєэъЎшш, ъюЄюЁvх эх тvчvтр¦Єё т ъръюь-ышсю ьхёЄх яЁюуЁрььv. (¦юфЁюсэхх юс ¤Єюь т Ёрчфхых 16.8.)
¦Ёш тvяюыэхэшш яЁюуЁрььр ¤Єюую яЁшьхЁр тvфрёЄ ёыхфє¦•шщ Ёхчєы№ЄрЄ:
[ 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
¦хїрэшчь °рсыюэют ьюцэю шёяюы№чютрЄ№ ш т эрёыхфєхьvї ъырёёрї. TюЄ ъръ тvуы фшЄ юяЁхфхыхэшх °рсыюэр ъырёёр ArrayRC:
#include <cassert>
#include "Array.h"
template <class elemType>
class ArrayRC : public Array<elemType> {
public:
ааа ArrayRC( int sz = DefaultArraySize )
ааааааааааа : Array<elemType>( sz ) {}
ааа ArrayRC( const ArrayRC& r )
ааааааааааа : Array<elemType>( r ) {}
ааа ArrayRC( const elemType *ar, int sz )
ааааааааааа : Array<elemType>( ar, sz ) {}
ааа elemType& ArrayRC<elemType>::operator[]( int ix )
ааа {
ааааааа assert( ix >= 0 && ix < Array<elemType>::_size );
ааааааа return _ia[ ix ];
ааа }
private:
// ...
};
¦юфёЄрэютър Ёхры№эvї ярЁрьхЄЁют тьхёЄю Єшяр-ярЁрьхЄЁр elemType яЁюшёїюфшЄ ъръ т срчютюь, Єръ ш т яЁюшчтюфэюь ъырёёрї. +яЁхфхыхэшх
ArrayRC<int> ia_rc(10);
тхфхЄ ёхс Єюўэю Єръ цх, ъръ юяЁхфхыхэшх IntArrayRC шч яЁхфvфє•хую Ёрчфхыр. Lчьхэшь яЁшьхЁ шёяюы№чютрэш шч яЁхфvфє•хую Ёрчфхыр. ¦Ёхцфх тёхую, ўЄюсv юяхЁрЄюЁ
// ЇєэъЎш¦ swap() Єюцх ёыхфєхЄ ёфхырЄ№ °рсыюэюь
swap( ia1, 1, ia1.size() );
сvы фюяєёЄшьvь, эрь яюЄЁхсєхЄё яЁхфёЄртшЄ№ ЇєэъЎш¦ swap() т тшфх °рсыюэр.
#include "Array.h"
template <class elemType>
inline void
swap( Array<elemType> &array, int i, int j )
{
а elemType tmp = array[ i ];
а array[ i ] = array[ j ];
а array[ j ] = tmp;
}
¦Ёш ърцфюь тvчютх swap() ухэхЁшЁєхЄё яюфїюф •р ъюэъЁхЄшчрЎш , ъюЄюЁр чртшёшЄ юЄ Єшяр ьрёёштр. TюЄ ъръ тvуы фшЄ яЁюуЁрььр, шёяюы№чє¦•р °рсыюэv Array ш ArrayRC:
#include <iostream>
#include "Array.h"
#include "ArrayRC.h"
template <class elemType>
inline void
swap( Array<elemType> &array, int i, int j )
{
а elemType tmp = array[ i ];
а array[ i ] = array[ j ];
а array[ j ] = tmp;
}
int main()
{
а Array<int>аа ia1;
а ArrayRC<int> ia2;
а cout << "swap() with Array<int> ia1" << endl;
а int size = ia1.size();
а swap( ia1, 1, size );
а cout << "swap() with ArrayRC<int> ia2" << endl;
а size = ia2.size();
а swap( ia2, 1, size );
а return 0;
}
LяЁрцэхэшх 2.13
¦єёЄ№ ьv шьххь ёыхфє¦•шх юс· тыхэш Єшяют:
template<class elemType> class Array;
enum Status { ... };
typedef string *Pstring;
+ёЄ№ ыш ю°шсъш т яЁштхфхээvї эшцх юяшёрэш ї юс·хъЄют?
(a) Array< int*& > pri(1024);
(b) Array< Array<int> > aai(1024);
(c) Array< complex< double > > acd(1024);
(d) Array< Status > as(1024);
(e) Array< Pstring > aps(1024);
LяЁрцэхэшх 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;
}
LяЁрцэхэшх 2.15
LьххЄё ёыхфє¦•шщ °рсыюэ ъырёёр:
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 Example2<elemType> &ex)
а { ex.print(os); return os; }
¦ръшх фхщёЄтш тvчvтр¦Є ёыхфє¦•шх шэёЄЁєъЎшш?
(a) Example2<Array<int>*> ex1;
(b) ex1.min (&ex1);
(c) Example2<int> sa(1024),sb;
(d) sa = sb;
(e) Example2<string> exs("Walden");
(f) cout << "exs: " << exs << endl;
LяЁрцэхэшх 2.16
¦ЁшьхЁ шч яЁхфvфє•хую єяЁрцэхэш эръырфvтрхЄ юяЁхфхыхээvх юуЁрэшўхэш эр Єшяv фрээvї, ъюЄюЁvх ьюуєЄ сvЄ№ яюфёЄртыхэv тьхёЄю elemType. Tръ,а ярЁрьхЄЁ ъюэёЄЁєъЄюЁр шьххЄ яю єьюыўрэш¦ чэрўхэшх 0:
explicit Example2 (elemType val=0) : _val(val) {};
+фэръю эх тёх Єшяv ьюуєЄ сvЄ№ шэшЎшрышчшЁютрэv эєыхь (эряЁшьхЁ, Єшя string), яю¤Єюьє юяЁхфхыхэшх юс·хъЄр
Example2<string> exs("Walden");
ты хЄё яЁртшы№эvь, р
Example2<string> exs2;
яЁштхфхЄ ъ ёшэЄръёшўхёъющ ю°шсъх[4]. Tръцх ю°шсюўэvь сєфхЄ тvчют ЇєэъЎшш min(), хёыш фы фрээюую Єшяр эх юяЁхфхыхэр юяхЁрЎш ьхэ№°х. T++ эх яючтюы хЄ чрфрЄ№ юуЁрэшўхэш фы Єшяют, яюфёЄрты хьvї т °рсыюэv. ¦ръ тv фєьрхЄх, сvыю сv яюыхчэvь шьхЄ№ Єръє¦ тючьюцэюёЄ№? +ёыш фр, яюяЁюсєщЄх яЁшфєьрЄ№ ёшэЄръёшё чрфрэш юуЁрэшўхэшщ ш яхЁхяш°шЄх т эхь юяЁхфхыхэшх ъырёёр Example2. +ёыш эхЄ, яю ёэшЄх яюўхьє.
LяЁрцэхэшх 2.17
¦ръ сvыю яюърчрэю т яЁхфvфє•хь єяЁрцэхэшш, яюяvЄър шёяюы№чютрЄ№ °рсыюэ Example2 ё Єшяюь, фы ъюЄюЁюую эх юяЁхфхыхэр юяхЁрЎш ьхэ№°х, яЁштхфхЄ ъ ёшэЄръёшўхёъющ ю°шсъх. +фэръю ю°шсър яЁю тшЄё Єюы№ъю Єюуфр, ъюуфр т ЄхъёЄх ъюьяшышЁєхьющ яЁюуЁрььv фхщёЄтшЄхы№эю тёЄЁхЄшЄё тvчют ЇєэъЎшш min(), т яЁюЄштэюь ёыєўрх ъюьяшы Ўш яЁющфхЄ єёях°эю. ¦ръ тv ёўшЄрхЄх, юяЁртфрэю ыш Єръюх яютхфхэшх? =х ыєў°х ыш яЁхфєяЁхфшЄ№ юс ю°шсъх ёЁрчє, яЁш юсЁрсюЄъх юяшёрэш °рсыюэр? ¦ю ёэшЄх ётюх ьэхэшх.