Д. Вандевурд, Н.М. Джосаттис - Шаблоны C++. Справочник разработчика (2003) (1160769), страница 49
Текст из файла (страница 49)
Полиморфизм, реализованный через шаблоны 261 14.2. Статический полиморфизм Например, функцию шуРгаи () чоЫ шуРгаи (ОеоОЬ» сопвеа оЬ» ) // ОеоОЬ» - абстрактный базовый класс ( оЬ».бган()у можно переписать следующим образом: Хешр1ахе «Хурепаше ОеоОЬ»> чохб шу)»гам(6еоОЬ» сопвга оЬ») // ОеоОЬ» - параметр шаблона ( оЬ» .с)гам() у Сравнивая обе реализации функции шу)»гам (), можно видеть, что основное различие состоит в указании ОвоОЬ» в качестве параметра шаблона вместо общего базового класса. Имеются, однако, и более существенные различия. Например, при использовании динамического полиморфизма в процессе выполнения у нас была только одна функция шу)»гам (), тогда как, применяя шаблон, мы имеем различные функции, такие,квашу)»гам<?хпе>() ишуРгаы<Схгс1е>(). Можно попытаться переписать весь пример из предыдущего раздела с использованием статического полнморфизма.
При этом вместо иерархии геометрических классов у нас появится несколько индивидуальных геометрических классов. // ро1у/вхагхсЬхег.Ьрр ((хпс1цс)е Ясоогс).ЬррЯ // Конкретный класс Схгс1е // - не порождается из какого-либо класса с1авв Схгс1е ( риЬ11с: чоЫ йгаы() сопиев Соогб сепсег об дгачхгу() сопвг~ // Конкретный класс Ьхце // - не порождается из какого-либо класса с1авв Ьхпе ( рцЬ1хс: чоЫ йгаи() сопиев Соогй сепхег ой дгач1ху() сопвх; 262 Глава 14. Полиморфные возможности шаблонов Применение этих классов теперь выглядит, как показано ниже. // ро1у/зсае1сро1у.срр ()1пс1цйе "зсас1сЬ1ег.Ьрр" ()1пс1ийе <чессог> // Черчение любого объекта 0еоОЬ5 сетр1аге <сурепке 0еоОЬ5> чо1й щупгаы(0еоОЬ5 сопзей оЬ5) ( оЬ5.йгам()> // Вызов йгам() соответствующего объекта // Расстояние между центрами тяжести двух объектов 0еоОЬ5 Еетр1асе <Гурепапе 0еоОЬ51, сурепке 0еоОЬ52> Соогй й1згапсе(0еоОЬ51 сопзеа х1, ОеоОЬ52 сопзеа х2) ( Соогй с = х1.сепсег об дгач1су() х2.сепгег об дгачфсу(); гееигп с.аЬз(); // Возврат абсолютного значения // Черчение однородной коллекции объектов 0еоОЬ5 сепр1аее <сурепаще 0еоОЬ5> чо1й йгамЕ1ещз(зей::чесгог<0еоОЬ5> сопзса е1ещз) ( бог (цпз1дпей 1 = Ор 1 < е1епш.з1пе(); ++1) ( // Вызов йгам() в соответствии с типом элемента е1еюз[1) .йгам(); 1пг пафп() ( Ь1пе 1; С1гс1е с, с1, с2у щупгаы(1) у // щупгаы<Ыпе>(0еоОЬ5й) => 11пе::йгам() щупгаы(с)р // юуЭгаы<С1гс1е>(0еоОЬ5а) => С1гс1е::йгам() й1згапсе(с1,с2); // й1зеапсе<С1гс1е, С1гс1е> (0еоОЬ51й,0еоОЬ52а) йазеапсе (1, с); 14.3.
Сравнение динамического и статического полиморфизма 263 // Мвсапсе<Ьйпе,С1кс1е>(ОеоОЬЗ1й,ОеоОЬЭ2й) // вой::чессок<0еоОЬЭ*> со11; // ОШИБКА: неоднородная коллекция невозможна вес(::чессок<Ыпе> со11> // Однородная коллекция со11.рцвЬ Ьас)с(1)з // Вставка линии с)каыЕ1ещв(со11)1 // Черчение всех линий ) Тип ОеоОЬ3 больше не может использоваться в качестве конкретного параметра типа как для функции с)1 всапсе ( ), так и в функции щупикам ( ) .
Вместо этого в функции сН в тапсе ( ) предусмотрены два параметра шаблона — ОеоОЬ3 1 и ОеоОЬ3 2. Два разных параметра шаблона позволяют вычислять расстояние между разными типами геометрических обьектов: й1всапсе(1,с) з // ййвсапсе<тйпе,сйкс1е>(6еоОЬ31й,8еоОЬ32й) Теперь, однако, разнородные коллекции больше не могут обрабатываться явным образом.
Это тот случай, когда статическая часть статического налимарфизма налагает свои ограничения, а именно: все типы должны быть определены в процессе компиляции. Взамен предоставляется возможность легко вводить разные коллекции для различных типов геометрических объектов, к тому же больше не требуется, чтобы коллекция была ограничена указателями, чгб дает существенные преимущества в аспекте производительности и безопасности типов. 14.3. Сравнение динамического и статического полиморфизма А теперь классифицируем и сравним обе формы полиморфизма.
Терминология Динамический и статический полиморфизм обеспечивает поддержку различных идиом языка программирования С++ . 3 ° Полиморфизм, реализованный с использованием наследования, является ограниченным (Ъонпг)ео) и динамическим (бупапйс). ° Термин ограниченный означает, что интерфейсы типов, участвующих в процессе полиморфизма, предопределены дизайном общего базового класса (другими терминами для обозначения данной концепции являются инваэивный (1пчаз(че) или интруэивный (/и!пьичв)). С терминологией, касающейся полиморфвзма, более детально можно ознакомиться в (12), Разлелы б.5-6.7. Глава 14. Полиморфные возможности шаблонов ° Термин динамический означает, что связывание интерфейсов происходит в процессе выполнения программы (т.е. динамически).
° Полиморфизм, реализованный с использованием шаблонов, является неограниченным (ппЬоппдед) и статическим (з1абс). ° Термин неограниченный означает, что интерфейсы типов, участвующих в процессе полиморфизма, не предопределены заранее (другими терминами для обозначения данной концепции являются неинвазивный (поп(пчаз(че) нли неинтрузивный (поппкпм(че)). ° Термин статический означает, что связывание интерфейсов происходит в процессе компиляции (т.е.
статически). Строго говоря, в терминах языка С++ понятия динамический полиморфизм и статический полиморфизм — это сокращенные варианты понятий ограниченный динамический полиморфизм и неограниченный статический полиморфизм. В других языках используются иные комбинации (например, Яша!!ш)1с использует термин "неограниченный динамический полиморфизм"). Однако более краткие термины динамический полиморфизм и статический полиморфизм в контексте языка С++ не приводят к возникновению путаницы. Преимущества н недостатки Динамический полиморфизм в С++ обладает рядом преимуществ.
° Элегантная обработка разнородных коллекций. ° размер исполняемого кода потенциально меньше (поскольку в данном случае нужна только одна полиморфная функция, тогда как для шаблонов с разными параметрами типов должны быль сгенерированы отдельные экземпляры). ° Код полностью компилируем; таким образом, исходные тексты не обязательно должны быль опубликованы (распространение библиотек шаблонов обычно требует распространения исходного кода реализации шаблонов). Приведем преимущества статического полиморфизма в С++. ° Легко реализуются коллекции встроенных типов. Общность интерфейса не обязательно должна выражаться через общий базовый класс. ° Сгенерированный код выполняется потенциально быстрее (поскольку априори отсутствует необходимость в косвенном обращении через указатели, а невиртуальные функции могут быть встраиваемыми намного чаще).
° Могут использоваться конкретные типы, в которых имеются только частичны~ интерфейсы (только если приложение ограничивается использованием этого частичного интерфейса). Часто статический полиморфизм расценивается как более надежный,в плане безопас ности типов, чем динамический, поскольку все связывания выполняются в процессе компиляции. Например, опасность того, что в контейнер, реализованный шаблоном, будет вставлен объект неправильного типа, крайне мала; в то же время в контейнере, кото- 14.4. Новые виды шаблонов проектирования 265 рый содержит указатели иа общий базовый класс, существует возможность иепредиамереииого использования указателей иа объекты совершенно иного типа На практике иистаицироваиие шаблонов может вызвать определенные неприятности в том случае, когда за идентично выглядящими интерфейсами скрываются разные семаитические допущеиия.
Например, неприятные сюрпризы могут произойти тогда, когда шаблон предполагает иаличие ассоциативного оператора+ у типа, который таким оператором ие обладает. Обычно этот вид семантического несоответствия встречается гораздо реже в иерархиях, основанных иа наследовании; вероятно, это связало с более явным и точным определением интерфейса. Объединение обеих форм Конечно, можно совместить обе формы наследования.
Например, различные виды геометрических объектов можно порождать из общего базового класса, для того чтобы иметь возможность обрабатывать неоднородные коллекции геометрических объектов. Однако одновременно можно использовать и шаблоны в целях написания кода для некоторого отдельного вида геометрического объекта. Комбинация наследования и шаблонов описана в главе 16, "Шаблоны и иаследоваиие". В ией рассматривается (помимо прочего), как может быть параметризоваиа виртуальиость функции-члена и как можно предоставить дополнительную гибкость статическому полиморфизму, используя основанную иа наследовании модель, необычного Рекуррентного шаблона (синопа(у гесиггсля сетр1асе рапегп — СЯТР).
14.4. Новые виды шаблонов проектирования Следствием использования новой формы статического полиморфизма являются иовые пути реализации шаблонов проектирования . Возьмем, например, шаблон ЬгЫйе 4 раиегл, который играет большую роль в программах иа С++. Одна из задач использоваиия этого шаблона проектироваиия состоит в переключении между различными реализациями иитерфейса. Согласно (13], обычно это переключение осуществляется с использоваиием указателя для обращения к действительной реализации и путем делегирования всех обращений к этому классу (рис.