Анимация
JavaScript
|
Главная Библионтека возвращаться значение, заданное по умолчанию return R(); Если нужно, чтобы выполнялись другие действия, достаточно заменить шаблон в классе Basevisi tab!е. 10.6.2. Нестрогое инспектирование Любой программист хотел бы иметь быстрые, независимые и гибкие инспекторы, способные читать его мысли и отличать обычную ошибку от вынужденного решения. С другой стороны, программисты ~ люди практичные, и с ними можно договориться. Гибкость стратегии catchAll вызывает зависть у пользователей шаблона visitor, предложенного группой GoF. Реализация этого шаблона весьма строга - она объявляет одну чисто виртуальную функцию для каждого инспектируемого типа. Каждую перегрузку функции visit нужно выводить из класса Basevisitor и реализовывать отдельно. Если это не сделать, код не будет компилироваться. Однако иногда инспектировать все типы, указанные в списке, совершенно не обязательно. Программисты хотят иметь выбор: либо реализовывать функцию visit для каждого типа, либо автоматически вызывать функцию OnUnknownVisitor для собственной реализации стратегии CatchAl 1. Для таких ситуаций библиотека Loki предусматривает класс Basevi si torlmpl. Он является производным от класса Basevisitor и использует адаптированные списки типов. Его реализацию можно найти в библиотеке Loki (файл visitor.h). 10.7. Резюме в главе обсуждался шаблон visitor и связанные с ним проблемы. По сушеству, шаблон visitor позволяет добавлять виртуальные функции в иерархию классов без модификации этих классов. В некоторых случаях шаблон visitor позволяет делать программы более ясными и гибкими. Однако с шаблоном visitor связано много проблем. Дело в том, что его можно применять лишь для очень устойчивых иерархий классов, для остальных иерархий это сделать практически невозможно. В этом случае можно воспользоваться шаблоном Acyclic visitor, пожертвовав эффективностью приложения. Используя тшательно продуманные и сложные приемы, можно создать обобщенную реализацию щаблона visitor. Сохраняя практически все преимущества шаблона visitor, его обобщенная реализация позволяет избежать многих проблем. В конкретных приложениях может оказаться полезным шаблон Acyclic visitor, правда, за счет снижения быстродействия программы. Если скорость работы приложения очень важна, следует использовать обобщенную реализацию шаблона visitor, облегчаюшую поддержку приложения (нужно контролировать ТОЛЬКО ОДИН ШСС) И Не замедляющую компиляцию. Обобщенная реализация использует самые совершенные приемы программирования на языке С++, такие как динамическое приведение типов, списки типов и частичная специализация. В результате появляется возможность выделить наиболее общие и повторяющиеся части реализации шаблона visitor в отдельную библиотеку. 10.8. Краткий обзор обобщенных компонентов шаблона Visitor • Для реализации шаблона Acyclic visitor используются классы Basevisitor (в качестве фиктивного базового класса), visitor и visitable. class Basevisitor; template <class т, typename R = void> class visitor; template < typename R = void, tempiate<class, class> CatchAll = DefaultCatchAll > class Basevisi table; • Первый шаблонный параметр классов visitor и Basevisitor задает тип значений, возвращаемых функциями-членами visit и Accept, соответственно. По умолчанию это - тип void (как в большинстве примеров, приведенных в книге GoF (2000), и описаний шаблона Visitor). • Вторым шаблонным параметром класса Basevi si table является стратегия перехвата (раздел 10.2). • Основу инспектируемой иерархии следует выводить из класса Basevi si table. Затем следует применять макрос DEFINE VISITABLE() в каждом классе иерархии или предусмотреть собственную реализацию функции Accept (Basevi si tors&). • Конкретные инспектирующие классы следует выводить из класса Basevisitor. Кроме того, их можно выводить из класса visitor<T> для каждого инспектируемого типа т. • Для "обычного" шаблона visitor следует применять шаблонный класс Cyclicvisitor: template <typename R, class TList> class Cyclicvisitor; • Инспектируемые типы нужно указывать в шаблонном аргументе TList. • Класс cyclicvisitor можно использовать наравне с классическим классом visitor. • Если нужно реализовать лишь отдельную часть шаблона visitor (нестрогий вариант), инспектируемую иерархию следует выводить из класса Basevi si-torimpl. Этот класс реализует все перегрузки функции visit, необходимые для вызова функции onUnknownvisitor. Часть этого класса можно замешать собственными функциями. Мультиметоды в этой главе определяются, обсуждаются и реализуются мультиметоды в контексте языка С++. Механизм виртуальных функций в языке С++ позволяет производить диспетчеризацию вызова в зависимости от динамического типа объекта. Мультиметоды предназначены для диспетчеризации вызова функции в зависимости от типов нескольких объектов. Для универсальной реализации языка необходима специальная поддержка. Именно так осуществляется реализация языков CLOS, ML, Haskell и Dylan. Однако в языке С++ такой поддержки нет, поэтому его эмуляция остается в компетенции разработчиков библиотек. В главе обсуждаются типичные решения и некоторые обобщенные реализации каждого из них. Эти решения представляют собой разные компромиссы между быстродействием, гибкостью и управлением зависимостями. Чтобы описать способ диспетчеризации вызова функции в зависимости от нескольких объектов, мы используем термин мультиметод (multimethod), позаимствованный у языка CLOS, и множественная диспетчеризация (multiple dispatch). В частности, множественная диспетчеризация для двух объектов называется двойной диспетчеризацией (double dispatch). Реализация мультиметодов - это чрезвычайно сложная и увлекательная задача, лишившая сна и покоя многих разработчиков и программистов. В главе рассматриваются следующие вопросы. • Определение мультиметодов. • Идентификация ситуаций, в которых необходимо применять полиморфизм мультиобъектов. • Обсуждение и реализация трех двойных диспетчеров, представляющих воплощения разных компромиссов. • Усовершенствование механизма двойной диспетчеризации. Прочитав эту главу, вы легко справитесь с типичными ситуациями, вынуждающими применять мультиметоды. Кроме того, вы сможете использовать и расширять некоторые надежные обобщенные компоненты, предоставленные библиотекой Loki, которые реализуют мультиметоды. Мы ограничимся обсуждением мультиметодов для двух объектов (двойная диспетчеризация). Овладев этой методикой, вы сможете самостоятельно распространить ее Если вам не удастся реализовать мультиметоды, рассматривайте эту главу в качестве снотворного средства, хотя я надеюсь, что она не обладает усыпляющим эффектом. 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 77 78 79 80 81 82 83 84 85 86 [ 87 ] 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |