Анимация
JavaScript
|
Главная Библионтека для того, чтобы получить 20-элементный массив из 10-элементных массивов. 157. Шаблоны классов должны обычно определять производные классы 158. Шаблоны не заменяют наследование; они его автоматизируют Главное, что нужно запомнить о шаблонах классов, - это то, что они порождают много определений классов. Как и всякий раз, когда у вас есть множество сходных определений классов, идентичные функции должны быть соединены в общий базовый класс. Во-первых, давайте взглянем на то, что не нужно делать. Класс storable, уже использованный мной, снова представляется хорошим примером. Сначала создадим объект collection для управления сохраняемыми объектами: class collection storable *head; public: ... storable *find( const storable &a match of this ) const; storable *collection::find( const storable &a match of this ) const Послать сообщение объекту начала списка, указывающее, что спи сок просматривается на совпадение со значением a match of this; return head ? head->find( a match of this ) : NULL Механизм поиска нужных объектов скрыт внутри класса storable. Вы можете изменить лежащую в основе структуру данных, поменяв определение storable, и эти изменения совсем не затронут реализацию класса collection. Затем давайте реализуем класс storable, использующий простой связанный список в качестве лежащей в основе структуры данных: class storable storable *next, *prev; 13 В действительности я бы использовал множественное наследование с участием класса string. Использованный здесь код имеет цель немного упростить пример. public: storable *find ( const storable &match of this ) const; storable *successor ( void ) const; virtual int operator== ( const storable &r ) const; storable *storable::find( const storable &match of this ) const Возвращает указатель на первый элемент в списке (начиная с себя), имеющий тот же ключ, что и match of this. Обычно, объект-коллекция должен послать это сообщение объекту начала списка, указатель на который хранится в классе коллекции. storable *current = this; for( ; current; current = current->next ) if( *current == match of this ) найдено совпадение return current; storable *storable::successor( void ) const Возвращает следующее значение в последовательности. return next; Функция operator==() должна быть чисто виртуальной, потому что отсутствует возможность ее реализации на уровне класса storable. Реализация должна быть выполнена в производном классе13 : class storable string : public storable string s; public: virtual int operator==( const storable &r ) const; ... virtual int operator==( const storable &r ) const storable string *right = dynamic cast<storable string *>( &r ); return right ? (s == r.s) : NULL; Я здесь использовал предложенный в ISO/ANSI Си++ безопасный механизм нисходящего приведения типов. right инициализируется значением NULL, если передаваемый объект (r) не относится к типу storable string. Например, он может принадлежать к некоторому См. пред1дущее примечание к правилу 156. - Ред. другому классу, также являющемуся наследником storable. Пока все идет хорошо. Теперь к проблемам, связанным с шаблонами. Кто-нибудь, не понимающий того, что делает, говорит: "Ребята, я могу исключить наследование и потребность в виртуальных функциях, используя шаблоны", а делает, вероятно, нечто подобное: template <class t key> class storable storable *next, *prev; t key key; public: ... storable *find ( const storable &match me ) const; storable *successor ( void ) const; int operator==( const storable &r ) const; template <class t key> int storable<t key>::operator==( const storable<t key> &r ) const return key == r.key ; template <class t key> storable<t key> *storable<t key>::successor( void ) const return next; template <class t key> storable *storable<t key>::find( const storable<t key> &match me ) const storable<t key> *current = this; for( ; current; current = current->next ) if( *current == match me ) найдено совпадение return current; Проблема здесь в непроизводительных затратах. Функции-члены шаблона класса сами являются шаблонами функций. Когда компилятор расширяет шаблон storable, он также расширяет варианты всех функций-членов этого шаблона*. Хотя я их не показал, вероятно, в классе storable определено множество функций. Многие из этих функций будут похожи в том, что они не используют информацию о типе, передаваемую в шаблон. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 [ 71 ] 72 73 74 75 76 |