• Единообразная работа, основанная на отношении надмножество/подмножество. Работа с различными классами, удовлетворяющими отношению надмножество/подмножество (базовый/производный), может выполняться единообразно. Функция, работающая с объектом Employee
(Служащий), будет работать и с объектами Secretary
(Секретарь).
• Статическая проверка типов. В С++ все типы проверяются статически.
• Динамическое связывание и раздельная компиляция. Код, который использует иерархию классов, может компилироваться отдельно от этой иерархии. Это становится возможным благодаря косвенности, обеспечиваемой указателями (как на объекты, так и на функции).
• Бинарная согласованность. Модули могут компоноваться как статически, так и динамически, до тех пор, пока схемы виртуальных таблиц подчиняются одним и тем же правилам.
Статический полиморфизм посредством шаблонов также позволяет значению иметь несколько типов. Внутри шаблона
template void f(T t) { /* ... */ }
t
может иметь любой тип, который можно подставить в f
для получения компилируемого кода. Это называется "неявным интерфейсом" в противоположность явному интерфейсу базового класса. Таким образом достигается та же цель полиморфизма — написание кода, который работает с разными типами — но совершенно иным путем.
Статический полиморфизм наилучшим образом подходит для решения следующих задач.
• Единообразная работа, основанная на синтаксическом и семантическом интерфейсе. Работа с типами, которые подчиняются синтаксическому и семантическому интерфейсу, может выполняться единообразно. Интерфейсы в данном случае представляют синтаксическую сущность и не основаны на сигнатурах, так что допустима подстановка любого типа, который удовлетворяет данному синтаксису. Например, пусть дана инструкция int i = p->f(5);
. Если p
— указатель на класс Base
, эта инструкция вызывает определенную функцию интерфейса, вероятно, virtual int f(int)
. Но если p
имеет обобщенный тип, то этот вызов может быть связан со множеством различных вещей, включая, например, вызов перегруженного оператора operator->
, который возвращает тип, в котором определена функция X f(double)
, где X
— тип, который может быть преобразован в int.
• Статическая проверка типов. Все типы проверяются статически.
• Статическое связывание (мешает раздельной компиляции). Все типы связываются статически.
• Эффективность. Вычисления во время компиляции и статическое связывание позволяют достичь оптимизации и эффективности, недоступных при динамическом связывании.
Определите ваши приоритеты и используйте каждый вид полиморфизма там, где проявляются его сильные стороны.
Следует сочетать статический и динамический полиморфизм для того, чтобы получить преимущества обоих видов полиморфизма, а не для того, чтобы комбинировать их недостатки.
• Статика помогает динамике. Используйте статический полиморфизм для реализации динамически полиморфных интерфейсов. Например, у вас может быть абстрактный базовый класс Command
, и вы определяете различные реализации в виде шаблона
template class ConcreteCommand: public Command
В качестве примеров можно привести реализации шаблонов проектирования Command
и Visitor
(см. [Alexandrescu01] и [Sutter04]).
• Динамика помогает статике. Обобщенный, удобный, статически связываемый интерфейс может использовать внутреннюю динамическую диспетчеризацию, что позволяет обеспечить одинаковую схему размещения объектов. Хорошими примерами могут служить реализации размеченных объединений (см. [Alexandrescu02b] и [Boost]) и параметр Deleter
у tr1::shared_ptr
(см. [C++TR104]).
• Прочие сочетания. Плохим является сочетание, при котором комбинируются слабые стороны обоих видов полиморфизма и результат получается хуже, чем при их отдельном использовании. Правильное сочетание должно комбинировать лучшее от обоих видов полиморфизма. Например, не помещайте виртуальные функции в шаблон класса, если только вы не хотите, чтобы каждый раз инстанцировались все виртуальные функции (в противоположность невиртуальным функциям шаблонных типов). В результате вы можете получить астрономический размер кода и чрезмерно ограничить ваш обобщенный тип, инстанцируя функциональность, которая никогда не используется.
Ссылки