Реализация в хедер .h файле или разделённая на .h и .cpp?

Подскажите пожалуйста, какая разница между тем, что я напишу реализацию какого то условного класса или функции в одном хедер файле или разделю их на реализацию в .cpp и прототип в .h ?

Правильно я понимаю, что если мне нет необходимости потом компилировать код в библиотеку, то разницы между этими методами абсолютно нет ?


Ответы (2 шт):

Автор решения: gbg

Различия можно раскидать условно на две стопки: различия технологические и человеческий фактор.

Главный технический фактор: это можно сделать не всегда. Отделение объявлений от реализации - это важная часть того, как работает компиляция на C++. Если у вас есть циклическая зависимость в объявлениях, вы будете вынуждены иногда использовать forward-declaration, а иногда - полное описание класса. Вот как раз вариант с отдельными файлами для объявления и реализации дает решение этого вопроса - в файле .h вы работаете с forward-declaration, в файле .cpp - с полным объявлением.

(Да, есть альтернативный вариант (предложен
@user7860670) при помощи ювелирной расстановки #include, но человеческий фактор мешает лично мне рассматривать его всерьез, так это требует от разработчика следования строгим правилам, иначе - матомный взрыв из нетривиальных ошибок в исполнении компилятора).

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

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

Далее уже всякая лирика:

Технически, тела всего что засунуто в объявление класса, будут расцениваться компилятором как inline, следовательно он будет пытаться, по возможности, затолкать эти тела прямо на место, откуда они вызываются - в зависимости от настроек оптимизации, разумеется. Это может повлиять на скорость работы программы и на ее размер, причем в любую сторону.

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

Теперь кратко про человеческий фактор - это уже вопрос привычки и вкуса.

→ Ссылка
Автор решения: user7860670

Реализация всего в заголовочных файлах известна как концепция SCU. В качестве преимуществ (для крупных проектов) вы получаете

  • Радикальное сокращение времени сборки. Это основная причина для перехода на SCU. Когда у вас есть проект с n единицами трансляции, время сборки будет расти ~линейно при добавлении каждой новой единицы трансляции. В то же время при использовании SCU время сборки будет расти только ~логарифмически и добавление новых классов в проект практически никак не будет сказываться на времени сборки.
  • Сокращение памяти, требуемой для сборки. Дисковой и оперативной. Хотя одна "большая" единица трансляции будет очевидно занимать куда больше места, чем любая из "маленьких", общий размер маленьких единиц трансляции будет куда больше.
  • Выигрыш по оптимизации. Очевидно, что все автоматически становится inline.
  • Пропадает страх случайно запустить пересборку всего проекта с 0. Это особенно важно в контексте Непрерывной Интеграции, так как это то, чем постоянно занимается CI сервер.

В качестве сложностей:

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

некоторые числа:

→ Ссылка