При делении кода на несколько файлов, что точно должно войти в.h файл и что должно войти в .cpp файл?
заголовочные файлы (. h
)) предназначены для предоставления информации, которая будет необходима в нескольких файлах. Такие вещи, как объявления классов, прототипы функций и перечисления обычно идут в заголовочных файлах. Одним словом, "определения".
Файлы кода (.cpp
) предназначены для предоставления информации о реализации, которая должна быть известна только в одном файле. В общем случае, тела функций и внутренние переменные, которые никогда не должны/не должны быть доступны другим модулям, являются тем, что принадлежит в файлах .cpp
. Одним словом, "реализации".
Самый простой вопрос, который можно задать себе, чтобы определить, что принадлежит, это "если я изменю это, мне придется изменить код в других файлах, чтобы заставить вещи компилироваться снова". Если ответ "да", то, вероятно, он принадлежит заголовочному файлу; если ответ "нет", то, вероятно, он принадлежит кодовому файлу
.То, что компилирует в ничто (нулевой двоичный отпечаток), попадает в заголовочный файл.
Переменные не компилируются в ничто, а с помощью объявлений типов (поскольку они описывают только поведение переменных).
функции не компилируют, а встроенные функции компилируют (или макросы), потому что они создают код только там, где вызываются.
шаблоны - это не код, это только рецепт создания кода. так что они также попадают в h-файлы.
. в дополнение ко всем остальным ответам, я скажу вам, что вы НЕ должны помещать в заголовочный файл:
с помощью
декларации (наиболее распространенной является с использованием пространства имён std;
) не должны появляться в заголовочном файле, так как они загрязняют пространство имён исходного файла, в который он включен.
Ваши объявления классов и функций плюс документация и определения для встроенных функций/методов (хотя некоторые предпочитают помещать их в отдельные .inl-файлы).
.В общем, вы помещаете объявления в заголовочный файл и определения в имплементационный (.cpp) файл. Исключением являются шаблоны, где определение также должно идти в заголовке.
Этот вопрос и подобные ему часто задавали на SO - см. Почему заголовочные файлы и .cpp файлы находятся в C++? и C++ заголовочные файлы, например, разделение кода.
.В основном заголовочный файл содержит скелет класса или декларацию (часто не меняется)
, а cpp-файл содержит реализацию класса (часто меняется).
заголовочный файл (.h) должен быть для деклараций классов, структур и их методов, прототипов и др. Реализация этих объектов производится в cpp.
in . h
class Foo {
int j;
Foo();
Foo(int)
void DoSomething();
}
Я бы ожидал увидеть:
, хотя на самом деле ответ - это то, что не следует вводить:
The header Defines something but doesn't tell anything about the implementation. ( Исключая шаблоны в этом "метафоре".
При этом нужно разделить "определения" на подгруппы, в данном случае есть два типа определений.
Теперь, конечно, я говорю о первой подгруппе.
В заголовке указана схема расположения вашей структуры, чтобы помочь остальному программному обеспечению использовать реализацию. Возможно, вы захотите рассматривать это как "абстракцию" вашей реализации, о которой говорят возмутительно, но я думаю, что в данном случае она вполне подходит.
Как было сказано и показано в предыдущих постерах, вы объявляете области частного и публичного использования и их заголовки, это также включает в себя частные и публичные переменные. Теперь я не хочу вдаваться в оформление кода, но, возможно, вам стоит подумать о том, что вы вставляете в заголовки, так как это Уровень между конечным пользователем и реализацией.
Заголовок (.h)
Тело (. cpp)
Rest of macros and includes
As a rule of thumb, you put the "shared" part on the .h (the part that other modules must be able to see) and the "not shared" part on the .cpp
PD: Yes, I've included global variables. Я использовал их несколько раз, и важно не определять их в заголовках, иначе вы получите множество модулей, каждый из которых определяет свою собственную переменную.
EDIT: Модифицировано после комментария David
.Дело в том, что на Си++ это несколько сложнее, чем организация заголовков/исходников на Си.
Компилятор видит один большой исходный (.cpp) файл с правильно включенными заголовками. Исходный файл - это единица компиляции, которая будет скомпилирована в объектный файл.
Потому что одной единице компиляции может понадобиться информация о реализации в другой единице компиляции. То есть можно записать, например, реализацию функции в одном исходном тексте, а объявление этой функции - в другом, нуждающемся в ее использовании.
В этом случае существует два экземпляра одной и той же информации. Что является злом...
Решение - поделиться некоторыми деталями. В то время как реализация должна остаться в Source, объявление общих символов, таких как функции, или определение структур, классов, перечислений и т.д.., Для размещения этих общих деталей используются заголовки.
Переместите в заголовок объявления о том, что нужно совместно использовать между несколькими источниками
В C++ есть некоторые другие вещи, которые можно поместить в заголовок, потому что они тоже должны быть общими:
Переместите в заголовок ВСЕ, что должно быть общим, включая общие реализации
Да. На самом деле, есть много разных вещей, которые могут быть внутри "заголовка" (i. e. shared between sources).
It becomes complicated, and in some cases (круговые зависимости между символами), impossible to keep it in one header. Заголовки можно разбить на три части
Это означает, что в крайнем случае можно иметь:
Представьте себе, что у нас есть шаблонированный 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.
В "реальной жизни" он обычно менее сложный. В большинстве случаев код будет иметь только простую организацию заголовков/кодов, с некоторыми инкассациями в исходном коде.
Но в других случаях (знающие друг друга шаблонные объекты), мне приходилось иметь для каждого объекта отдельные заголовки деклараций и реализаций, с пустым исходным кодом, включающим эти заголовки, только для того, чтобы помочь мне увидеть некоторые ошибки компиляции.
Другой причиной разбиения заголовков на отдельные заголовки может быть ускорение компиляции, ограничение количества разобранных символов до строго необходимого и избежание ненужной перекомпиляции исходного текста, который заботится только о прямом объявлении, когда изменяется реализация встроенного метода.
Необходимо сделать организацию кода как можно более простой и модульной. Положите как можно больше в исходный файл. Выставляйте только в заголовках то, что нужно совместно использовать.
Но в тот день, когда у вас появятся круговые зависимости между шаблонированными объектами, не удивляйтесь, если ваша организация кода станет несколько более "интересной", чем обычная организация заголовков/кодов...
^_^
.