Абстрактные классы против шаблонов - хорошие практики

Допустим, у меня есть некоторый класс, который представляет алгоритм, и этот алгоритм требует чего-то особенного из данных (например, некоторая функция-член).

В примере мы можем сделать:

                                          <<interface>>
+------------------------+               +------------+
|       Algorithm        |    <<uses>>   |    Data    |
+------------------------+-------------->+------------+
| + doJob(inData : Data) |               | +getPixel()|
+------------------------+               +------------+

И мы можем заставить пользователя Algorithm наследовать от Data каждый раз, когда он хочет использовать алгоритм класса. Мы также можем сделать шаблон:

template<typename T>
doJob(T&& inputData){
   //implementation
}

(функция без класса, чтобы упростить вещи)

И мы заставляем нашего клиента создавать классы, у которых есть методы с собственным именем, но мы не заставляем его реализовывать наш абстрактный класс (интерфейс на разных языках) (возможно, немного лучшую производительность?)

И мой вопрос:

Какой подход лучше?

  • Если у нас есть выбор, следует ли нам реализовывать вещи шаблонным или абстрактным способом в библиотеке?

  • Есть ли причина для стандарта не определять некоторые стандартные "Интерфейсы", такие как std::container или std::factory (только примеры)?

2 ответа

Решение

На самом деле у вас есть более одного вопроса, поэтому давайте ответим на них один за другим:

Какой подход лучше?

Ни один не лучше в целом. У каждого есть свои сильные и слабые стороны. Но вы подошли к интересному моменту: на более абстрактном уровне эти два практически одинаковы.

Если у нас есть выбор, следует ли нам реализовывать вещи шаблонным или абстрактным способом в библиотеке?

С шаблонами вы получаете:

  1. В общем, более быстрое исполнение. Это может быть намного быстрее, потому что много встраивания, а затем можно провести оптимизацию. OTOH, с продвинутым компилятором / компоновщиком де-виртуализации и функциями, которые не могут быть сильно встроены / оптимизированы, вы можете получить почти такую ​​же скорость.

  2. Более медленные времена компиляции. Это может быть намного медленнее, особенно если вы идете по пути "необычного шаблона-мета-программирования".

  3. Хуже ошибки компилятора. Они могут быть намного хуже, особенно если вы идете по пути "модного шаблонного метапрограммирования". Когда C++ получает поддержку концепций, следует избегать этого.

  4. Если вы разрабатываете это тщательно, улучшенная безопасность типов. OTOH, если вы не будете осторожны, вы в конечном итоге будете печатать на утке хуже, чем Smalltalk. Концепции могут быть инструментом, который может помочь и здесь.

С виртуальными функциями / интерфейсами вы получаете:

  1. Разделенный дизайн, где, если вы будете осторожны, изменения из одного файла не потребуют повторной компиляции других, а время компиляции может быть намного быстрее.
  2. Полиморфизм во время выполнения, что означает, что вы можете динамически загружать код (это не так просто, как кажется, но это возможно)
  3. Что-то, что выглядит более знакомым для тех, кто имеет опыт в ОО.

Есть ли причина для стандарта не определять некоторые стандартные "Интерфейсы", такие как std::container или std::factory (только примеры)?

Я думаю, можно найти много "низкоуровневых" причин, но фундаментальная причина - производительность. Таким образом, STL был спроектирован так, чтобы быть "настолько быстрым, насколько это возможно", а поставить некоторые (полезные) интерфейсы "сверху, если это" сейчас практически невозможно.

Кажется, это вопрос, основанный на мнении. Лучший способ заставить клиента выполнить свои обязательства - заставить его подписать контракт, этот контакт является интерфейсом.

Другие вопросы по тегам