Стандартная практика С++: классы виртуального интерфейса и шаблоны
Я должен принять решение относительно обобщения и полиморфизма.
Ну, сценарий стандартный: я хочу сделать свой монолитный взаимозависимый
код должен быть более модульным, чистым и расширяемым.
Он все еще находится в стадии, когда изменение принципа дизайна выполнимо,
и, смотря на это, очень желательно.
Я буду вводить чисто виртуальные базовые классы (интерфейсы) или шаблоны?
Мне известно об основах выбора шаблона:
меньше косвенности, лучшей производительности, более компиляции
но
без позднего связывания и т.д.
stl не использует много (или нет?) наследования, а boost тоже не работает.
Но я думаю, что они нацелены на то, чтобы быть очень маленькими базовыми инструментами, которые используются каждый
2 строки кода программистом.
Я считаю, что подход наследования и позднего связывания более разумен для
подключаемый стиль больших фрагментов кода и функциональность, которые должны быть взаимозаменяемыми,
обновляемый и т.д. после развертывания или даже во время выполнения.
Ну, мой сценарий в некоторой степени заключен между собой.
Мне не нужно обмениваться кусочками кода "на лету" во время выполнения, время компиляции в порядке.
Обычно это также очень центральная и часто используемая функциональность,
он не логически разделяется на большие блоки.
Это позволяет мне несколько придать шаблонному решению.
Для меня это также выглядит несколько чище.
Есть ли какие-то большие плохие последствия, все еще интерфейсы
идти? Когда они не?
Что больше соответствует стандарту С++?
Я знаю, что это граничит с субъективным, но меня действительно интересует
некоторый опыт. У меня нет копии Скотта Мейера, эффективного С++
поэтому я возлагаю надежды на вас, ребята:)
Ответы
Ответ 1
Вы в основном правы, динамический полиморфизм (наследование, виртуальные), как правило, является правильным выбором, когда тип должен быть разрешен для изменения во время выполнения (например, в плагиновых архитектурах). Статический полиморфизм (шаблоны) является лучшим выбором, если тип должен изменяться только во время компиляции.
Единственным возможным недостатком шаблонов является то, что 1) они обычно должны быть определены в заголовках (что означает, что больше кода получает #include), и это часто приводит к более медленному времени компиляции.
Но конструктивно, я не вижу никаких проблем с использованием шаблонов, когда это возможно.
Что больше соответствует стандарту С++ стиль?
Зависит от того, что такое "стандартный стиль С++". Стандартная библиотека С++ использует немного всего. STL использует шаблоны для всего, немного более старая библиотека IOStreams использует наследование и виртуальные функции, а функции библиотеки, унаследованные от C, не используют, конечно.
В наши дни шаблоны являются, безусловно, самым популярным выбором, и я должен сказать, что это самый "стандартный" подход.
Ответ 2
Свойства классического объектно-ориентированного полиморфизма:
- объекты привязаны во время выполнения; это более гибко, но также потребляет больше ресурсов (ЦП) во время выполнения
- сильная типизация привносит несколько более безопасный тип, но необходимость
dynamic_cast
(и его возможность взорвать лицо клиента) может легко компенсировать это.
- вероятно, более широко известны и поняты, но "классические" иерархии глубокого наследования кажутся мне ужасающими.
Свойства полиморфизма времени компиляции по шаблону:
- привязка времени компиляции позволяет более агрессивно оптимизировать, но предотвращает гибкость во время выполнения
- Утиная печать может показаться более неудобной, но ошибки обычно являются сбоями во время компиляции.
- иногда бывает труднее читать и понимать; без понятий, диагностика компилятора может иногда становиться раздражающей.
Обратите внимание, что нет необходимости принимать решение для одного. Вы можете свободно смешивать и смешивать их обоих (и многие другие идиомы и парадигмы). Часто это приводит к очень внушительному (и выразительному) коду. (См., Например, такие вещи, как стирание стилей.) Чтобы понять, что возможно благодаря умному смешиванию парадигм, вы можете просмотреть Alexandrescu "Modern С++ Design".
Ответ 3
Это что-то вроде ложной оппозиции. Да, основное использование наследования и виртуальных функций находится в iostreams
, которые очень старые и написаны в совершенно другом стиле для остальных библиотек std
.
Но многие из самых "классных" современных библиотек С++, таких как boost, используют полиморфизм во время выполнения, они просто используют шаблоны, чтобы сделать его более удобным для использования.
boost::any
и std::tr1::function
(ранее также из boost) являются прекрасными примерами.
Они представляют собой контейнеры с одним элементом для чего-то, чей конкретный тип неизвестен во время компиляции (это особенно заметно при использовании any
, потому что у него есть свой собственный динамический оператор-оператор, чтобы получить значение).
Ответ 4
После того, как вы перекусили немного больше опыта на моей тарелке, в шаблонах, которые мне не нравятся, есть некоторые вещи:
Существуют определенные недостатки, которые дисквалифицируют метапрограммирование шаблона как пригодный для использования язык:
- читаемость: слишком много скобок, слишком много неязыковых принудительных (поэтому неправильно используемых) соглашений
- для тех, кто проходит обычную эволюцию в языках программирования, шаблоны нечитабельны и непонятны (просто посмотрите на boost bgl)
- Иногда кажется, что кто-то пытался написать генератор кода С++ в awk.
- сообщения об ошибках компилятора - cl (utter) ed crap
- слишком много необходимых хаков (большинство из них исправлено в С++ 0x), чтобы получить базовые "языковые" функции.
- Нет шаблонов в файлах реализации, в результате чего в библиотеках только заголовка (который является очень двухсторонним мечом)
- обычные функции завершения кода IDE не очень помогают шаблонам.
- Выполнение большого материала в MPL кажется "худшим", не может найти для него другого слова. Каждая строка шаблонного кода создает ограничения на этот тип шаблона, которые принудительно применяются в способе замены текста. Есть семантика, присущая иерархиям наследования, в структурах шаблонов нет. Он, как и все, является void *, и компилятор пытается сказать вам, будет ли segfault.
Все сказанное, я использую его довольно успешно в основных утилитах и библиотеках. Написание высокоуровневой функциональности или связанных с ней аппаратных средств, похоже, не сокращает ее для меня.
Это означает, что я строю свои строительные блоки, но построю дом классическим способом.
Ответ 5
С моей точки зрения, это то, на что вы лучше всего. Если у вас больше опыта работы с OO, используйте OO. Если у вас больше опыта с дженериками, используйте дженерики.
Оба метода имеют несколько эквивалентных шаблонов, которые означают для многих вещей, которые вы можете использовать. EG Strategy in OO vs Policy in Generics или Template Method в OO по сравнению с обычным повторяющимся шаблоном шаблона в дженериках.
Если вы планируете код генерации рефакторинга, который уже работает, но структура немного вонючая. Не используйте его в качестве предлога для игры с какой-то новой техникой дизайна, потому что через год или два, как только вы лучше поймете технику, вы можете пожалеть о том, как вы реорганизовали свой код. Очень легко вводить новые негибкости при применении техник, когда вы их изучаете. Цель состоит в том, чтобы улучшить дизайн существующего кода, если у вас нет навыков в технике, как вы знаете, что улучшаете дизайн, а не создаете в своем коде большой фаллический символ.
Лично я лучше в OO и, как правило, предпочитаю его, поскольку я знаю, что могу создавать чистые проекты, которые легко понять и что большинство людей может изменить. Самый общий код, который я правильно, нацелен на взаимодействие с другим общим кодом, например, с написанием итератора или общей функцией для алгоритмов.
Ответ 6
Я использую оба в моей большой базе кода. Когда тип известен во время компиляции, я проектирую его с помощью шаблонов, когда он известен только во время выполнения, я использую виртуальные функции. Я считаю, что виртуальные функции легче программировать и легче читать позже, однако времена, когда производительность критическая, и тот факт, что шаблонный полиморфизм (если вы действительно можете назвать его полиморфизм) может быть встроен, действительно помогает.