|
Программирование >> Полиморфизм без виртуальных функций в с++
слово, помогающее распознать шаблон, так что такого рода ухищрения оказались излишними. Угловые скобки <. . . > были выбраны вместо фигурных по ряду причин: во-первых, .многим пользователям казалось, что они легче читаются; во-вторых, как уже от.мечалось выше, фигурные скобки и так часто используются в синтаксисе С и С-ы-. Тем не менее существовала определенная проблема. В предложении List<List<int>> а; на первый взгляд, объявляется список списков целых. На самом деле, это синтаксическая ошибка, поскольку лексема (сдвиг вправо или оператор вывода) - не то же самое, что две лексемы >. Разумеется, простой лексический трюк решил бы данную проблему, но я решил не запутывать ни гра.мматику, ни лексический анализатор. Однако с тех пор эта ошибка встречалась так часто, что теперь я испытываю сильнейшее желание ликвидировать проблему. 15.8. Методы композиции Шаблоны поддерживают несколько безопасных и весьма мощных приемов ко.мпозиции. Напри.мер, это средство можно применять рекурсивно: template<class Т> class List { /* ... */ }; List<int> li; List< List<int> > Hi; List< List< List<int> > > llli; Если нужны конкретные составные типы, то их легко определить с помощью наследования: template<class Т> class List2 : public List< List<T> > { }; template<class T> class List3 : public List2< List<T> > { }; List2<int> 1112; List3<int> 11113; Подобное использование наследования несколько необычно, поскольку не добавляется никаких новых членов. Наследование не сопряжено с дополнительными расходами времени или памяти; это всего лишь метод композиции. Если бы композицию нельзя было осуществить с помощью наследования, то для шаблонов пришлось бы изобрести какие-то особые механизмы композиции, иначе язык оказался бы гораздо беднее. Переменные данных составных типов можно использовать точно так же, как и соответствующие определенные типы, но не наоборот: void f() { Hi = 1112; правильно 1112 = Hi; ошибка Причина - открытое наследование определяет отношение подтипа. Для того чтобы разрешить присваивание в обоих направлениях, понадобилось бы расширение языка, вводящее настоящие параметризованные синонимы. Например: template<class Т> typedef List< List<T> > List4; void {List< List<T> >& Istl, List4& lst2) { Istl = lst2; lst2 = Istl; Технически такое расширение реализовать несложно, но вряд ли стоит вводить еще одно средство для переименования. Также благодаря наследованию можно частично задавать аргументы шаблонов в определении нового типа: template<class U, class V> class X ( /* ... */ }; template<class U> class XX : public X<U,int> { }; В обычном случае наследование от шаблона класса позволяет подправить базовый класс с помощью информации, нужной производному классу. Благодаря этому К0.МП03ИЦИЯ становится более гибкой. Например: template<class Т> class Base { /* ... */ }; class Derived : public Base<Derived> { /* ... */ }; Описанная методика позволяет информации о производном классе попадать в определение базового класса. См. также раздел 14.2.7. 15.8.1. Представление стратегии реализации Еще одно применение наследования и шаблонов для композиции - .метод передачи объектов, представляющих стратегии реализации. Напри.мер, семантику сравнения для сортировки или средства распределения и освобождения памяти для контейнера можно было бы задать с помощью аргументов шаблона [2пс1]: Один из возможных способов - использовать шаблон для составления нового клосса из интерфейса для нужного контейнера и класса распределителя памяти, применяя технику размещения, описанную в [2nd, §6.7.2]: template<class Т, class А> class Controlled container : public Container<T>, private A { ... void some function() { ... T* p = new(A::operator new(sizeof(T))) T; .. . ... Здесь необходимо использовать шаблон, поскольку мы проектируем контейнер. Наследование от класса Container необходимо, чтобы Controlled container можно было использовать в качестве контейнера. Использование аргумента шаблона А позволяет применять различные распределители. Например: class Shared : public Arena { /* ... */ } ; class Fast allocator { /* ... */ }; class Persistent : public Arena { /* ... */ } ; Controlled container<Process descriptor,Shared> ptbl; Controlled container<Node,Fast allocator> tree; Controlled container<Personnel record,Persistent> payroll; Это обычный способ передать нетривиальную информацию о реализации производному классу. Преимущества приема - систематичность и возможность использовать встраивание. Правда, в данном случае нередко возникают довольно длинные имена. Но для них можно ввести синонимы с помощью typedef . В компонентах Буча [Booch, 1993] такой способ композиции используется повсеместно. 15.8.2. Представление отношений порядка Рассмотрим задачу сортировки. У нас есть шаблон контейнера, тип элемента и функция, сортирующая элементы в контейнере. Мы не можем поместить критерий сортировки внутрь контейнера, поскольку обычно хранящиеся в нем элементы не должны зависеть от него. У нас также нет воз.можности поместить этот критерий и внутри типа элементов, поскольку их можно сортировать разными способами. Итак, критерий сортировки не встраивается ни в контейнер, ни в тип элемента. Вместо этого он передается в виде операции, которую следует выполнить. Если в качестве примера взять строки, состоящие из слов - личных шведских имен, тогда какую схему упорядочения применить для сравнения? Для шведского языка обычно применяются две разные схемы. Но нет сомнения, что нельзя давать сведения о соглашениях, принятых для такой операции, ни общему типу строки, ни общему алгоритму сортировки. Таким образом, любое общее решение включает выраженный в общих терминах алгоритм сортировки, который можно определить не для конкретного типа, а для конкретного использования данного типа. Давайте, например, обобщим стандартную библиотечную функцию strcmp () для работы со строками любого типа Т. Сначала определяется шаблон класса с семантикой сравнения объекта типа т по умолчанию: template<class Т> class CMP { public: static int eq(T a, T b) { return a==b; } static int lt{T a, T b) { return a<b; }
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |