2.5. Использование шаблоновНаш класс IntArray служит хорошей альтернативой встроенному массиву целых чисел.
Но в жизни могут потребоваться массивы для самых разных типов данных. Можно
предположить, что единственным отличием массива элементов типа double от нашего
является тип данных в объявлениях, весь остальной код совпадает буквально. template <class elemType> class Array { public: explicit Array( int sz = DefaultArraySize ); Array( const elemType *ar, int sz ); Array( const Array &iA ); Ключевое слово template говорит о том, что задается шаблон, параметры которого
заключаются в угловые скобки (<>). В нашем случае имеется лишь один параметр
elemType; ключевое слово class перед его именем сообщает, что этот параметр
представляет собой тип. #include <iostream> #include "Array.h" Здесь определены три экземпляра класса Array: Array<int> ia(array_size); Array<double> da(array_size); Array<char> ca(array_size); Что делает компилятор, встретив такое объявление? Подставляет текст шаблона Array, заменяя параметр elemType на тот тип, который указан в каждом конкретном случае. Следовательно, объявления членов приобретают в первом случае такой вид: // Array<int> ia(array_size); int _size; int *_ia; Заметим, что это в точности соответствует определению массива IntArray. // Array<double> da(array_size); int _size; double *_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" Подстановка реальных параметров вместо типа-параметра elemType происходит как в базовом, так и в производном классах. Определение ArrayRC<int> ia_rc(10); ведет себя точно так же, как определение IntArrayRC из предыдущего раздела.
Изменим пример использования из предыдущего раздела. Прежде всего, чтобы оператор swap( ia1, 1, ia1.size() ); был допустимым, нам потребуется представить функцию swap() в виде шаблона. #include "Array.h" template <class elemType> inline void swap( Array<elemType> &array, int i, int j ) { При каждом вызове swap() генерируется подходящая конкретизация, которая зависит от типа массива. Вот как выглядит программа, использующая шаблоны Array и ArrayRC: #include <iostream> #include "Array.h" #include "ArrayRC.h" template <class elemType> Упражнение 2.13Пусть мы имеем следующие объявления типов: template<class elemType> class Array; enum Status { ... }; typedef string *Pstring; Есть ли ошибки в приведенных ниже описаниях объектов? (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); Упражнение 2.14Перепишите следующее определение, сделав из него шаблон класса: class example1 { public: example1 (double min, double max); example1 (const double *array, int size); Упражнение 2.15Имеется следующий шаблон класса: template <class elemType> class Example2 { public: explicit Example2 (elemType val=0) : _val(val) {}; bool min(elemType value) { return _val < value; } Какие действия вызывают следующие инструкции? (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; Упражнение 2.16Пример из предыдущего упражнения накладывает определенные ограничения на типы данных, которые могут быть подставлены вместо elemType. Так, параметр конструктора имеет по умолчанию значение 0: explicit Example2 (elemType val=0) : _val(val) {}; Однако не все типы могут быть инициализированы нулем (например, тип string), поэтому определение объекта Example2<string> exs("Walden"); является правильным, а Example2<string> exs2; приведет к синтаксической ошибке . Также ошибочным будет вызов функции min(), если для данного типа не определена операция меньше. С++ не позволяет задать ограничения для типов, подставляемых в шаблоны. Как вы думаете, было бы полезным иметь такую возможность? Если да, попробуйте придумать синтаксис задания ограничений и перепишите в нем определение класса Example2. Если нет, поясните почему. Упражнение 2.17Как было показано в предыдущем упражнении, попытка использовать шаблон Example2 с типом, для которого не определена операция меньше, приведет к синтаксической ошибке. Однако ошибка проявится только тогда, когда в тексте компилируемой программы действительно встретится вызов функции min(), в противном случае компиляция пройдет успешно. Как вы считаете, оправдано ли такое поведение? Не лучше ли предупредить об ошибке сразу, при обработке описания шаблона? Поясните свое мнение. Назад ВпередСодержание |
Нет комментариев. Оставить комментарий: |