Есть ли альтернативы полиморфизму в C ++? - PullRequest
8 голосов
/ 25 февраля 2009

CRTP предлагается в этом вопросе о динамическом полиморфизме. Тем не менее, эта модель предположительно полезна только для статического полиморфизма. Кажется, что дизайн, на который я смотрю, быстро ограничивается вызовами виртуальных функций, как намекает . Ускорение даже в 2,5 раза было бы фантастическим.

Рассматриваемые классы просты и могут быть полностью встроены в код, однако до времени выполнения неизвестно, какие классы будут использоваться. Кроме того, они могут быть прикованы цепью в любом порядке, что приводит к травмированию производительности.

Любые предложения (в том числе, как можно использовать CRTP в этом случае) приветствуются.

Редактировать: Google прибегает к упоминанию о шаблонах функций. Это выглядит многообещающе.

Ответы [ 3 ]

18 голосов
/ 25 февраля 2009

Полиморфизм буквально означает множественные (поли) формы (морфы). В статически типизированных языках (таких как C ++) существует три типа полиморфизма.

  1. Adhoc полиморфизм: это лучше всего видно в C ++ как перегрузка функций и методов. Одно и то же имя функции будет привязано к разным методам на основе сопоставления типа времени компиляции параметров вызова функции или сигнатуры метода.
  2. Параметрический полиморфизм: в C ++ это шаблоны и все забавные вещи, которые вы можете с ним сделать, такие как CRTP, специализация, частичная специализация, метапрограммирование и т. Д. Опять же, этот тип полиморфизма, когда одно и то же имя шаблона может делать разные вещи на по параметрам шаблона время компиляции полиморфизм.
  3. Полиморфизм подтипа: наконец, это то, о чем мы думаем, когда слышим слово полиморфизм в C ++. Здесь производные классы переопределяют виртуальные функции, чтобы специализировать поведение. Указатель одного и того же типа на базовый класс может иметь различное поведение в зависимости от конкретного производного типа, на который он указывает. Это способ получить полиморфизм времени выполнения в C ++.

Если до времени выполнения неизвестно, какие классы будут использоваться, вы должны использовать полиморфизм подтипа, который будет включать вызовы виртуальных функций.

Вызовы виртуальных методов имеют очень небольшие издержки производительности по сравнению со статически связанными вызовами Я призываю вас посмотреть на ответы на этот ТАК вопрос.

3 голосов
/ 25 февраля 2009

Я согласен с m-sharp, что вы не избежите полиморфизма во время выполнения.

Если вы цените оптимизацию выше элегантности, попробуйте заменить скажем

void invoke_trivial_on_all(const std::vector<Base*>& v)
{
  for (int i=0;i<v.size();i++)
    v[i]->trivial_virtual_method();
}

с чем-то вроде

void invoke_trivial_on_all(const std::vector<Base*>& v)
{
  for (int i=0;i<v.size();i++)
  {
    if (v[i]->tag==FooTag)
      static_cast<Foo*>(v[i])->Foo::trivial_virtual_method();
    else if (v[i]->tag==BarTag)
      static_cast<Bar*>(v[i])->Bar::trivial_virtual_method();
    else...
  }
}

это не красиво, конечно, не ООП (скорее, возвращение к тому, что вы могли бы сделать в старом добром 'C'), но если виртуальные методы достаточно тривиальны, вы должны получить функцию без вызовов (при условии достаточно хорошего компилятора и оптимизации опции). Вариант с использованием dynamic_cast или typeid может быть немного более элегантным / безопасным, но имейте в виду, что эти функции имеют свои собственные издержки, которые в любом случае, вероятно, сопоставимы с виртуальным вызовом.

Скорее всего, вы увидите улучшение по сравнению с вышеописанным, если некоторые методы классов не используются, и это избавило вас от их вызова, или если функции содержат общий код, инвариантный к циклам, и оптимизатору удается его поднять. из цикла.

0 голосов
/ 25 февраля 2009

Вы можете пойти по маршруту Оле С и использовать союзы. Хотя это тоже может быть грязно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...