При разделении кода на несколько файлов, что именно должно помещаться в файл .h, а что - в файл .cpp?
.hpp
файл, а объявления C - в .h
файл. Это очень полезно при смешивании кода C и C ++ (например, унаследованных модулей в C).
При разделении кода на несколько файлов, что именно должно помещаться в файл .h, а что - в файл .cpp?
.hpp
файл, а объявления C - в .h
файл. Это очень полезно при смешивании кода C и C ++ (например, унаследованных модулей в C).
Ответы:
Заголовочные файлы ( .h
) предназначены для предоставления информации, которая потребуется в нескольких файлах. Такие вещи, как объявления классов, прототипы функций и перечисления, обычно помещаются в файлы заголовков. Одним словом, «определения».
Файлы кода ( .cpp
) предназначены для предоставления информации о реализации, которая должна быть известна только в одном файле. В общем, тела функций и внутренние переменные, которые не должны / никогда не должны быть доступны другим модулям, принадлежат .cpp
файлам. Одним словом, «реализации».
Самый простой вопрос, который нужно задать себе, чтобы определить, что принадлежит и где находится: «Если я изменю это, мне придется изменить код в других файлах, чтобы снова компилировать вещи?» Если ответ «да», он, вероятно, принадлежит заголовочному файлу; если ответ «нет», он, вероятно, принадлежит файлу кода.
export
). Единственный способ обойти №1 - это PIMPL. # 2 был бы возможен, если бы export
поддерживался, и может быть возможно с использованием c ++ 0x и extern
шаблонов. IMO, файлы заголовков в С ++ теряют большую часть своей полезности.
Дело в том, что в C ++ это несколько сложнее, чем организация заголовка / источника C.
Компилятор видит один большой исходный файл (.cpp) с правильно включенными заголовками. Исходный файл - это единица компиляции, которая будет скомпилирована в объектный файл.
Потому что одному модулю компиляции может потребоваться информация о реализации в другом модуле компиляции. Таким образом, можно написать, например, реализацию функции в одном источнике и написать объявление этой функции в другом источнике, в котором необходимо ее использовать.
В этом случае есть две копии одной и той же информации. Что зло ...
Решение - поделиться некоторыми подробностями. Хотя реализация должна оставаться в источнике, объявление общих символов, таких как функции, или определение структур, классов, перечислений и т. Д., Может потребоваться совместно.
Заголовки используются для размещения этих общих деталей.
Переместите в заголовок объявления о том, что нужно разделить между несколькими источниками
В C ++ есть и другие вещи, которые можно поместить в заголовок, потому что они тоже должны быть общими:
Переместите в заголовок ВСЕ, чем нужно поделиться, включая общие реализации
Да. На самом деле, есть много разных вещей, которые могут быть внутри «заголовка» (т. Е. Разделены между источниками).
Это становится сложным, а в некоторых случаях (циклические зависимости между символами) невозможно сохранить его в одном заголовке.
Это означает, что в крайнем случае у вас могут быть:
Представим, что у нас есть шаблонный объект MyObject. У нас могло быть:
// - - - - MyObject_forward.hpp - - - -
// This header is included by the code which need to know MyObject
// does exist, but nothing more.
template<typename T>
class MyObject ;
.
// - - - - MyObject_declaration.hpp - - - -
// This header is included by the code which need to know how
// MyObject is defined, but nothing more.
#include <MyObject_forward.hpp>
template<typename T>
class MyObject
{
public :
MyObject() ;
// Etc.
} ;
void doSomething() ;
.
// - - - - MyObject_implementation.hpp - - - -
// This header is included by the code which need to see
// the implementation of the methods/functions of MyObject,
// but nothing more.
#include <MyObject_declaration.hpp>
template<typename T>
MyObject<T>::MyObject()
{
doSomething() ;
}
// etc.
.
// - - - - MyObject_source.cpp - - - -
// This source will have implementation that does not need to
// be shared, which, for templated code, usually means nothing...
#include <MyObject_implementation.hpp>
void doSomething()
{
// etc.
} ;
// etc.
В «реальной жизни» это обычно не так сложно. Большая часть кода будет иметь только простую организацию заголовка / источника с некоторым встроенным кодом в исходном коде.
Но в других случаях (шаблонные объекты, знающие друг друга) мне приходилось иметь для каждого объекта отдельное объявление и заголовки реализации с пустым источником, включая эти заголовки, просто чтобы помочь мне увидеть некоторые ошибки компиляции.
Еще одна причина разбить заголовки на отдельные заголовки может заключаться в ускорении компиляции, ограничении количества анализируемых символов до необходимого количества и избежании ненужной перекомпиляции источника, который заботится только о прямом объявлении при изменении реализации встроенного метода.
Вы должны сделать организацию кода как можно более простой и как можно более модульной. Поместите как можно больше в исходный файл. В заголовках указывайте только то, чем нужно поделиться.
Но в тот день, когда у вас возникнут циклические зависимости между шаблонными объектами, не удивляйтесь, если ваша организация кода станет несколько более "интересной", чем простая организация заголовка / источника ...
^ _ ^
в дополнение ко всем другим ответам я скажу вам, что вы НЕ помещаете в файл заголовка:
using
объявление (наиболее распространенное using namespace std;
) не должно появляться в файле заголовка, потому что они загрязняют пространство имен исходного файла, в который он включен .
using
для переноса чего-либо в глобальное пространство имен в заголовке.
static inline
в C99, потому что что-то связано с тем, что происходит, когда вы объединяете внутреннюю связь с шаблонами. Пространства имен Anon позволяют «скрывать» функции, сохраняя при этом внешнюю связь.
То, что компилируется в ничто (нулевой двоичный след), попадает в файл заголовка.
Переменные не компилируются в ничто, но объявления типов делают (потому что они описывают только поведение переменных).
функции нет, но встроенные функции (или макросы) делают это, потому что они создают код только там, где они вызываются.
шаблоны - это не код, это всего лишь рецепт для создания кода. поэтому они также входят в h-файлы.
Как правило, объявления помещаются в файл заголовка, а определения - в файл реализации (.cpp). Исключением являются шаблоны, определение которых также должно быть в заголовке.
Этот и похожие на него вопросы часто задаются в SO - см. Почему в C ++ используются файлы заголовков и файлы .cpp? и файлы заголовков C ++, например , разделение кода .
Объявления ваших классов и функций, а также документация и определения встроенных функций / методов (хотя некоторые предпочитают помещать их в отдельные файлы .inl).
В основном файл заголовка содержит скелет или объявление класса (не часто меняется)
а файл cpp содержит реализацию класса (часто меняется).
Я ожидал увидеть:
на самом деле ответ заключается в том, что не нужно вставлять:
Заголовок что-то определяет, но ничего не говорит о реализации. (За исключением шаблонов в этом "метафоре".
С учетом сказанного, вам нужно разделить «определения» на подгруппы, в данном случае есть два типа определений.
Теперь я, конечно, говорю о первой подгруппе.
Заголовок предназначен для определения макета вашей структуры, чтобы помочь остальной части программного обеспечения использовать реализацию. Возможно, вы захотите увидеть это как «абстракцию» вашей реализации, что шутливо сказано, но я думаю, что в данном случае это вполне подходит.
Как было сказано и показано в предыдущих плакатах, вы объявляете частные и общедоступные области использования и их заголовки, это также включает частные и общедоступные переменные. Я не хочу здесь вдаваться в разработку кода, но вы можете подумать о том, что вы вставляете в свои заголовки, поскольку это уровень между конечным пользователем и реализацией.
Заголовок (.h)
Тело (.cpp)
Как правило, вы помещаете «совместно используемую» часть модуля в .h (часть, которую должны видеть другие модули), а «не разделяемую» часть в .cpp.
ПД: Да, я включил глобальные переменные. Я использовал их несколько раз, и важно не определять их в заголовках, иначе вы получите много модулей, каждый из которых определяет свою собственную переменную.
РЕДАКТИРОВАТЬ: изменено после комментария Дэвида