|
Программирование >> Инициализация объектов класса, структура
class LongSouble { public: LongDouble( double dbval ) : value( dval ) { } bool compareLess( const LongDouble & ); private: double value; Предположим, что шаблон класса Queue нужно конкретизировать таким типом: Но в этом классе нет оператора operator<() , позволяющего сравнивать два значения типа LongDouble, поэтому использовать для очереди типа Queue<LongDouble> функции-члены min() и max() нельзя. Одним из решений этой проблемы может стать определение глобальных operator<() и operator>() , в которых для сравнения значений типа Queue<LongDouble> используется функция-член compareLess. Эти глобальные операторы вызывались бы из min() и max() автоматически при сравнении объектов из очереди. Однако мы рассмотрим другое решение, связанное со специализацией шаблонов класса: вместо общих определений функций-членов min() и max() при конкретизации шаблона Queue типом LongDouble мы определим специальные экземпляры Queue<LongDouble>::min() и Queue<LongDouble>::max() , основанные на функции-члене compareLess() класса LongDouble. Это можно сделать, если воспользоваться явным определением специализации, где после ключевого слова template идет пара угловых скобок <>, а за ней - определение специализации члена класса. В приведенном примере для функций-членов min() и max() класса Queue<LongDouble>, конкретизированного из шаблона, определены явные специализации: Следующая инструкция в функции-члене min() сравнивает два элемента очереди Queue: pq->item < min val Здесь неявно присутствует требование к типам, которыми может конкретизироваться шаблон класса Queue: такой тип должен либо иметь возможность пользоваться предопределенным оператором меньше для встроенных типов, либо быть классом, в котором определен оператор operator<() . Если же этого оператора нет, то попытка применить min() к очереди приведет к ошибке компиляции в том месте, где вызывается несуществующий оператор сравнения. (Аналогичная проблема существует и в miax(), только касается оператора operator>() ). определения явных специализаций template<> LongDouble Queue<LongDouble>::min() { assert( ! is empty() ); LongDouble min val = front->item; for ( QueueItem *pq = front->next; pq != 0; pq = pq->next ) if ( pq->item.compareLess( min val ) ) min val = pq->item; return min val; template<> LongDouble Queue<LongDouble>::max() { assert( ! is empty() ); LongDouble max val = front->item; for ( QueueItem *pq = front->next; pq != 0; pq = pq->next ) if ( max val.compareLess( pq->item ) ) max val = pq->item; return max val; Хотя тип класса Queue<LongDouble> конкретизируется по шаблону, в каждом объекте этого типа используются специализированные функции-члены min() и max() - не те, что конкретизируются по обобщенным определениям этих функций в шаблоне класса Queue. Поскольку определения явных специализаций min() и max() - это определения невстроенных функций, помещать их в заголовочн1й файл нельзя: они обязаны находится в файле с текстом программы. Однако явную специализацию функции можно объявления явных специализаций функций-членов template <> LongDouble Queue<LongDouble>::min(); объявить, не определяя. Например: template <> LongDouble Queue<LongDouble>::max(); Поместив эти объявления в заголовочный файл, а соответствующие определения - в исходный, мы можем организовать код так же, как и для определений функций-членов обычного класса. Иногда определение всего шаблона оказывается непригодным для конкретизации некоторым типом. В таком случае программист может специализировать шаблон класса целиком. Напишем полное определение класса Queue<LongDouble>: QueueLD.h: определяет специазацию класса Queue<LongDouble> #include Queue.h template<> Queue<LongDouble> { Queue<LongDouble>(); ~Queue<LongDouble>(); LongDouble& remove(); void add( const LongDouble & ); bool is empty() const; LongDouble min(); LongDouble max(); private: Некоторая реазация Явную специализацию шаблона класса можно определять только после того, как общий шаблон уже был объявлен (хотя и не обязательно определен). Иными словами, должно быть известно, что специализируемое имя обозначает шаблон класса. Если в приведенном примере не включить заголовочный файл Queue.h перед определением явной специализации шаблона, компилятор выдаст сообщение об ошибке, указывая, что Queue - это не имя шаблона. Если мы определяем специализацию всего шаблона класса, то должны определить также все без исключения функции-члены и статические данные-члены. Определения членов из общего шаблона никогда не используются для создания определений членов явной специализации: множества членов этих шаблонов могут различаться. Чтобы предоставить определение явной специализации для типа класса Queue<LongDouble>, придется определить не только функции-члены min() и max() , но и все остальные. Если класс специализируется целиком, лексемы template<> помещаются только перед #include QueueLD.h определяет функцию-член min() из специализированного шаблона класса определением явной специализации всего шаблона: LongDouble Queue<LongDouble>::min() { } Класс не может в одних файлах конкретизироваться из общего определения шаблона, а в других - из специализированного, если задано одно и то же множество аргументов. Например, специализацию шаблона QueueItem<LongDouble> необходимо объявлять в ----Filel.C---- #include Queue.h void ReadIn( Queue<LongDouble> *pq ) { использование pq->add() приводит к конкретизации QueueItem<LongDouble> каждом файле, где она используется:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |