Каковы преимущества и недостатки реализации классов в заголовочных файлах?

Мне нравится концепция DRY (не повторяйте себя [упс]), но концепция заголовочных файлов в C++ противоречит этому правилу программирования. Есть ли какой-либо недостаток для определения члена класса полностью в заголовке? Если это правильно для шаблонов, почему не для обычных классов? У меня есть несколько идей по поводу недостатков и преимуществ, но какие у вас?

6 ответов

Решение

Возможные преимущества размещения всего в заголовочных файлах:

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

Возможные недостатки размещения всего в заголовочных файлах:

  • Более длинные циклы компиляции / компоновки
  • Потеря разделения интерфейса и реализации
  • Может привести к трудно разрешаемым круговым зависимостям
  • Много встраивания может увеличить размер исполняемого файла
  • Предотвращает двоичную совместимость разделяемых библиотек /DLL
  • Расстраивает коллег, которые предпочитают традиционные способы использования C++

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

Ты не повторяешься. Вы пишете код только один раз в одном заголовке. Это повторяется препроцессором, но это не ваша проблема, и это не является нарушением DRY.

Если это правильно для шаблонов, почему не для обычных классов

Это не совсем то, что нужно делать с шаблонами. Это единственный, который действительно работает в целом.

В любом случае, если вы реализуете класс в заголовке, вы получаете следующие преимущества и недостатки:

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

И... вот и все, правда.

Большая часть моего кода имеет тенденцию быть в заголовках, но это потому, что большая часть моего кода - шаблоны.

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

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

Основным недостатком (кроме длинных сборок) является отсутствие четкого разделения интерфейса и реализации.

В идеале вам не нужно видеть реализацию интуитивно понятного и хорошо документированного интерфейса.

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

Есть альтернатива:
Делайте много вещей в классах, объявленных в вашем исходном файле. 1 пример - это pimpl-idiom, но есть также люди, которые боятся объявлять классы из заголовочного файла. Тем не менее, это имеет смысл для частных классов.

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