А. Александреску - Современное проектирование на C++ (1119444), страница 67
Текст из файла (страница 67)
сеер1ате турепаее л = чо10. теер1ате <сурепаее, с1ава> с1аав сасспл11 оеГац1тсасспл11 > с1аэз вазеч1з1сао1е как и раньше ... теер1ате <с1аьз т> зсат1с кетцгптуре лссерттер1(тб ч1з1себ, вазеч1з1согб диезе) ( 1Р (ч1э1сог<т> р = дупае1с саэт<ч1з1тог<т>*>(едцезт)) ( гетцгп р->ч1з1с(ч1з1тед); // изменение гетцгп сасспл11<к, т>::опцпкпонпч1з1тог(ч1з1теб, диезт); Стратегия сапс|зл11 вполне соответствует требованиям шаблона.
Она может возвращать значение по умолчанию или кол ошибки, генерировать исключительную ситуацию, вызывать виртуальную функцию-член для инспектируемого объекта, пьпаться выполнять динамическое приведение типов и т.д. Реализация функции опцпкпоипч1 збсог значительно зависит от нужд конкретного приложения. В некоторых случаях необходимо, чтобы инспектирование было выполнено для всех типов, входящих в иерархию. В других случаях это относится лишь к некоторым типам, а остальные можно проигнорировать. В реализации шаблона асус11с ч1ззсог в основном применяется второй подход, поэтому по умолчанию стратегия сатспл11 имеет следующий вид.
теер1асе <с1азз к, с1авз ч1з1сед> зсгцст оеУац1тсатспл11 зтас1с л опцпкиоипч1з1сог(ч1з1тедб, вазеч1з1согб) ( // здесь указывается действия, которые следует // предпринять при несоответствии между инспектором и // и инспектируемым объектом. обычно должно 278 Часть!1. Компоненты // возвращаться значение, заданное по умолчанию гетцгп яо; Если нужно, чтобы выполнялись другие действия, достаточно заменить шаблон в классе вазечззй саЫе.
10.6.2. Нестрогое инспектирование Любой программист хотел бы иметь быстрые, независимые и гибкие инспекторы, способные читать его мысли и отличать обычную ошибку от вынужденного решения. С другой стороны, программисты — люди практичные, и с ними можно договориться. Гибкость стратегии сатспя11 вызывает зависть у пользователей шаблона ч1з1тог, предложенного группой Сор. Реализация этого шаблона весьма строга †- она объявляет одну чисто виртуальную функцию для каждого инспектируемого типа.
Каждую перегрузку функции чйззт нужно выводить из класса вазеч1Мтог и реализовывать отдельно. Если это не сделать, код не будет компилироваться. Однако иногда инспектировать все типы, указанные в списке, совершенно не обязательно. Программисты хотят иметь выбор; либо реализовывать функцию ч1 зйт лля каждого типа, либо автоматически вызывать функцию опцпКпоипч1з1тог для собственной реализации стратегии сатспя11. Для таких ситуаций библиотека Еок1 предусматривает класс вазечззйтогтмр1.
Он является производным от класса вазечйззтог и использует адаптированные списки типов. Его реализацию можно найти в библиотеке Еок| (файл чйзйгог. Ь). 10.?. Резюме В главе обсуждался шаблон Избтог и связанные с ним проблемы, По сушеству, шаблон чтзттог позволяет добавлять виртуальные функции в иерархию классов без модификации этих классов. В некоторых случаях шаблон ч1Мтог позволяет делать программы более ясными и гибкими. Однако с шаблоном Из1тог связано много проблем.
Дело в том, что его можно применять лишь для очень устойчивых иерархий классов, для остальных иерархий это сделать практически невозможно. В этом случае можно воспользоваться шаблоном ясус1 т с И зт тог, пожертвовав эффективностью приложения. Используя тшательно продуманные и сложные приемы, можно создать обобшенную реализацию шаблона чтзттог. Сохраняя пракгически все преимушества шаблона ч1зт тог, его обобшенная реализация позволяет избежать многих проблем. В конкретных приложениях может оказаться полезным шаблон ясус1тс Из1тог, правда, за счет снижения быстродействия программы. Если скорость работы приложения очень важна, следует использовать обобшенную реализацию шаблона Мз тсог, облегчаюшую поддержку приложения 1нужно коцтролиррддуд |о~а«р олй~ «~дгг) // ис замедляюшую компиляцию. Обоб енная ш нная реализация использует самые совершенные приемы программирования на языке С++, такие как динамическое приведение типов, списки типов и частичная специализация.
В результате появляется возможность выделить наиболее обшие и повторяюшиеся части реализации шаблона чйзттог в отдельную библиотеку. 279 Гпава 10. Шаблон Иа11ог 10.8. Краткий обзор обобщенных компонентов шаблона Иа(тог ° Для реализации шаблона асус11с ч151сог используются классы вазеч(51сог (в качестве фиктивного базового класса), ч151сог и ч151саЫе. с1а55 вазеч151сог; севр1асе <с1ааа т, Сурепаве и = уо(д> с1а55 ч151сог; севр!асе < Сурепаве я = Уо1д, севр)асе<с1а55, С1а55> Сагспд11 = цеГао1ссассМ11 > с1а55 вазеч151саб!е; ° Первый шаблонный параметр классов ч151сог и вазеч151сог задает тип значений, возвращаемых функциями-членами У151с и ассерс, соответственно.
По умолчанию это — тип уо10 (как в большинстве примеров, приведенных в книге Оор (2000), и описаний шаблона ч151сог). ° Вторым шаблонным параметром класса вазеч151саб!е является стратегия перехвата (раздел 10.2). ° Основу инспектируемой иерархии следует выводить из класса вазеч151саЫе. Затем следует применять макрос реГХне У151тлв1 ее в каждом классе иерархии или предусмотреть собственную реализацию функции ассерс(вазеч15(согзб).
° Конкретные инспектирующие классы следует выводить из класса вазеч151сог. Кроме тото, их можно выводить из класса ч151сог<т> для каждого инспектируемого типа т. ° Для "обычного" шаблона У151сог следует применять шаблонный класс сус! 1 сч1 51 сот: гевр1асе <сурепаве я, с1а55 тг15с> с1а55 сус11сч151сог; ° Инспектируемые типы нужно указывать в шаблонном аргументе тг15С. ° Класс сус11сч151сог можно использовать наравне с классическим классом У151сог. ° Если нужно реачизовать лишь отдельную часть шаблона У151сог (нестрогий вариант), инспектируемую иерархию следует выводить из класса вазеч151- гогсвр1, Этот класс реализует все перегрузки функции ч151с, необходимые для вызова функции опцп(~поипч151сог, Часть этого класса можно замешать собственными функциями.
280 Часть П. Компоненты МУЛЬТИ МЕТОДЫ В этой главе опрелеляются, обсуждаются и реализуются мультиметоды в контексте языка С++, Механизм виртуальных функций в языке С++ позволяет пронзволить диспетчери- зацию вызова в зависимости от динамического типа объекта. Мультиметолы предна- значены для диспетчеризации вызова функции в зависимости от типов несколько» объектов. Зля универсальной реализации языка необходима специальная поддержка.
Именно так осуществляется реализация языков СЕОБ, М1., Найс!! и Оу!ап. Однако в языке С++ такой поддержки нет, поэтому его эмуляция остается в компетенции раз- работчиков библиотек. В главе обсуждаются типичные решения и некоторые обобщенные реализации ка- жлого из них. Эти решения представляют собой разные компромиссы между быстро- действием, гибкостью и управлением зависимостями. Чтобы описать способ диспет- черизации вызова функции в зависимости от нескольких объектов, мы используем термин»г»гьлгцметод (ого!1!пгег)гог!), позаимствованный у языка С! ОБ, н множествен- ная дислелгче)гизация (пш!йр!е г)!враге)г). В частности, множественная диспетчеризация для двух объектов называется двойной дислетчеризицией (оооЫе г)!враге)г). Реализация мультиметодов — это чрезвычайно сложная и увлекательная задача, лишившая сна и покоя многих разработчиков и программистов.' В главе рассматриваются следующие вопросы, ° Определение мультиметодов.
° Идентификация ситуаций, в которых необходимо применять полиморфизм м ул ьти объектов. ° Обсуждение и реализация трех двойных диспетчеров, представляющих воплощения разных компромиссов. ° усовершенствование механизма двойной диспетчеризации. Прочитав эту главу, вы легко справитесь с типичными ситуациями, вынуждающи- ми применять мультиметоды. Кроме того, вы сможете использовать и расширять не- которые надежные обобшенные компоненты, предоставленные библиотекой ).о)г), ко- торые реализуют мультиметоды. Мы ограничимся обсуждением мультиметодов для двух объектов (двойная диспет- черизация).