Стандартная практика c ++: classы виртуального интерфейса и шаблоны

Я должен принять решение относительно обобщения и polymorphismа.

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

Я буду вводить чисто виртуальные базовые classы (интерфейсы) или шаблоны?

Я знаю об основах относительно опции шаблона: меньше косвенности, лучшей производительности, большей компиляции, но без поздней привязки и т. Д.

Stl не использует много (или нет?) Наследования, а boost тоже. Но я думаю, что они нацелены на то, чтобы быть очень маленькими базовыми инструментами, которые программисты используют каждые 2 строки кода.

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

Ну, мой сценарий лежит несколько между ними.

Мне не нужно обмениваться кусочками кода «на лету» во время выполнения, время компиляции в порядке. Обычно это также очень центральная и часто используемая функциональность, она не логически разделяется на большие блоки.

Это позволяет мне несколько придать шаблонному решению. Для меня это также выглядит несколько чище.

Есть ли какие-то большие плохие последствия, интерфейсы по-прежнему? Когда они не? Что больше соответствует стандарту c ++?

Я знаю, что это граничит с субъективным, но я действительно заинтересован в некоторых переживаниях. У меня нет копии Скотта Мейерса, эффективного C ++, поэтому я возлагаю надежды на вас, ребята 🙂

    Вы в основном правы, динамический polymorphism (наследование, виртуальные машины), как правило, является правильным выбором, когда тип должен быть разрешен для изменения во время выполнения (например, в плагиновых архитектурах). Статический polymorphism (шаблоны) является лучшим выбором, если тип должен изменяться только во время компиляции.

    Единственный возможный недостаток шаблонов заключается в том, что 1) они обычно должны быть определены в заголовках (что означает, что больше кода получает #included), и это часто приводит к более медленному времени компиляции.

    Но конструктивно, я не вижу никаких проблем с использованием шаблонов, когда это возможно.

    Что больше соответствует стандарту c ++?

    Зависит от того, что такое «стандартный стиль C ++». Стандартная библиотека C ++ использует немного всего. STL использует шаблоны для всего, немного более старая библиотека IOStreams использует наследование и виртуальные функции, а функции библиотеки, унаследованные от C, не используют, конечно,.

    В наши дни шаблоны, безусловно, являются самым популярным выбором, и я должен сказать, что это самый «стандартный» подход.

    Свойства classического объектно-ориентированного polymorphismа:

    • объекты привязаны во время выполнения; это более гибко, но также потребляет больше ресурсов (ЦП) во время выполнения
    • сильная типизация привносит несколько более безопасный тип, но потребность в dynamic_cast (и его возможность взорвать лицо клиента) может легко компенсировать это
    • вероятно, более широко известны и поняты, но «classические» глубокие иерархии наследования кажутся мне ужасающими

    Свойства polymorphismа времени компиляции по шаблону:

    • привязка времени компиляции позволяет более агрессивно оптимизировать, но предотвращает гибкость во время выполнения
    • утиная печать может показаться более неудобной, но сбои обычно являются сбоями во время компиляции
    • иногда бывает труднее читать и понимать; без понятий, диагностика компилятора может иногда становиться яростной

    Обратите внимание, что нет необходимости принимать решение ни для одного. Вы можете свободно смешивать и смешивать их обоих (и многие другие идиомы и парадигмы). Часто это приводит к очень внушительному (и выразительному) коду. (См., Например, такие вещи, как стирание стилей.) Чтобы получить представление о том, что возможно благодаря умному смешиванию парадигм, вы можете просмотреть «Современный дизайн C ++» Александреску.

    Это что-то вроде ложной оппозиции. Да, основное использование наследования и виртуальных функций в iostreams , которые очень старые и написаны в совершенно другом стиле для остальных библиотек std .

    Но многие из «самых classных» современных библиотек C ++, таких как boost, используют polymorphism во время выполнения, они просто используют шаблоны, чтобы сделать его более удобным в использовании.

    boost::any и std::tr1::function (ранее также из boost) – прекрасные примеры.

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

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

    • читаемость: слишком много скобок, слишком много неязыковых принудительных (поэтому неправильно используемых) соглашений
    • для тех, кто проходит обычную эволюцию в языках программирования, шаблоны нечитабельны и непонятны (просто посмотрите на boost bgl)
    • Иногда кажется, что кто-то пытался написать генератор кода c ++ в awk.
    • сообщения об ошибках компилятора cl (utter) ed crap
    • слишком много необходимых хаков (большинство из них исправлено в c ++ 0x), чтобы получить базовые «языковые» функции.
    • Нет шаблонов в файлах реализации, в результате чего в библиотеках только заголовка (который является очень двухсторонним мечом)
    • обычные функции завершения кода IDE не очень помогают шаблонам.
    • Выполнение большого материала в MPL кажется «худым», не может найти для него другого слова. Каждая строка шаблонного кода создает ограничения на этот тип шаблона, которые принудительно применяются в способе замены текста. Есть семантика, присущая иерархиям наследования, в структурах шаблонов нет. Это похоже на то, что все является void *, и компилятор пытается сказать вам, будет ли segfault.

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

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

    Оба метода имеют несколько эквивалентных шаблонов, которые означают для многих вещей, которые вы можете использовать. EG Strategy in OO vs Policy in Generics или Template Method в OO по сравнению с обычным повторяющимся шаблоном шаблона в дженериках.

    Если вы планируете создать код для производства рефакторинга, который уже работает, но структура немного вонючая. Не используйте его в качестве предлога для игры с какой-то новой техникой дизайна, потому что через год или два, как только вы лучше поймете технику, вы можете пожалеть о том, как вы реорганизовали свой код. Очень легко вводить новые негибкости при применении техник, когда вы их изучаете. objective состоит в том, чтобы улучшить дизайн существующего кода, если у вас нет опыта в технике, как вы знаете, что улучшаете дизайн, а не создаете большой фаллический символ в своем коде.

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

    Я использую оба в моей большой базе кода. Когда тип известен во время компиляции, я проектирую его с помощью шаблонов, когда он известен только во время выполнения, я использую виртуальные функции. Я считаю, что виртуальные функции легче программировать и легче читать позже, однако бывают моменты, когда производительность критическая, и тот факт, что шаблонный polymorphism (если вы действительно можете назвать его polymorphism) может быть встроен, действительно помогает.