Мне нравится помещать весь мой #includes в мой заголовочный файл затем, только включают мой заголовок для того исходного файла в моем исходном файле. Каков промышленный стандарт? Есть ли, кто-либо тянет спины к моему методу?
Как правило, вы хотите поместить в файл заголовка класса только минимум необходимых включений, так как любой, кто использует этот заголовок, будет вынужден #include
их все. В более крупных проектах это приводит к более медленным сборкам, проблемам с зависимостями и всевозможным неприятностям.
Думайте о файле заголовка как о публичном интерфейсе вашего класса. Вы не хотите обременять всех, кто его использует, дополнительными зависимостями, если только они не необходимы , чтобы иметь возможность использовать класс.
Переместите все, что требуется только в реализации класса, в исходный файл. Для других классов, используемых в заголовке, только #include
их заголовки, если вам действительно нужно знать их размер или содержимое в заголовке - все остальное и предварительное объявление ] достаточно. В большинстве случаев вам нужно только #include
классов, от которых вы наследуете, и классов, объекты которых являются членами-значениями вашего класса.
Эта страница содержит хорошее резюме. (Реплицируется ниже для справки)
Большие программные проекты требуют тщательного управления заголовочными файлами даже при программировании на C. Когда разработчики переходят на C ++, управление заголовочными файлами становится еще более сложным и требует много времени. Здесь мы представляем несколько шаблонов включения файла заголовка, которые упростят эту работу.
Здесь мы обсуждаем основные правила включения файла заголовка C ++, необходимые для упрощения управления файлом заголовка.
Файл заголовка следует включать только в том случае, если предварительное объявление не сработает.
Файл заголовка должен быть спроектирован таким образом, чтобы порядок включения файла заголовка не имел значения.
Это необходимо. достигается путем проверки того, что xh
является первым файлом заголовка в x.cpp
Механизм включения файла заголовка должен быть устойчивым к дублированию включения файла заголовка. {{1} } В следующих разделах эти правила объясняются на примере.
В следующем примере показаны различные типы зависимостей. Предположим, что это класс A с кодом, хранящимся в a.cpp
и a.h
.
ah
#ifndef _a_h_included_
#define _a_h_included_
#include "abase.h"
#include "b.h"
// Forward Declarations
class C;
class D;
class A : public ABase
{
B m_b;
C *m_c;
D *m_d;
public:
void SetC(C *c);
C *GetC() const;
void ModifyD(D *d);
};
#endif
a.cpp
#include "a.h"
#include "d.h"
void A::SetC(C* c)
{
m_c = c;
}
C* A::GetC() const
{
return m_c;
}
void A::ModifyD(D* d)
{
d->SetX(0);
d->SetY(0);
m_d = d;
}
Давайте проанализируем включения файла заголовка с точки зрения классов, задействованных в этом примере, то есть ABase
, A
, B
, C
и D
.
ABase
- это базовый класс, поэтому объявление класса требуется для завершения объявления класса. Компилятору необходимо знать размер ABase
, чтобы определить общий размер A
. В этом случае abase.h
следует явно включить в a.h
. A
содержит класс B
по значению, поэтому объявление класса требуется для завершения объявления класса. Компилятору необходимо знать размер B, чтобы определить общий размер A
. В этом случае b.h
следует явно включить в a.h
. Класс C
включен только в качестве ссылки на указатель. Размер или фактическое содержимое C
не важны для a.h
или a.cpp
. Таким образом, в a.h
было включено только предварительное объявление. Обратите внимание, что c.h
не был включен ни в a.h
, ни в a.cpp
. D
используется просто как ссылка на указатель в a.h
. Таким образом, достаточно предварительного объявления. Но a.cpp
по сути использует класс D
, поэтому он явно включает d.h
. Заголовочные файлы следует включать только в том случае, если предварительное объявление не работает. Не включая ch
и dh
других клиентов класса A
, никогда не придется беспокоиться о ch
и dh
, если только они используют по значению классы C и D.
ah
был включен в качестве первого файла заголовка в a.cpp
Это гарантирует, что ah
] не ожидает, что определенные файлы заголовков будут включены до ах
. Поскольку ah
был включен в качестве первого файла, успешная компиляция a.cpp
гарантирует, что ah
не ожидает, что какой-либо другой файл заголовка будет включен до ah
.
Если это выполняется для всех классов, (например, x.cpp
всегда включает x.h
в качестве первого заголовка) не будет зависимости от включения файла заголовка.
a.h
включает проверку определения препроцессором символа _a_h_included_
. Это делает его устойчивым к дублированию включений a.h
.
Циклическая зависимость существует между классами X
и Y
в следующем примере. Эта зависимость обрабатывается с помощью предварительных объявлений.
x.h и y.h
/* ====== x.h ====== */
// Forward declaration of Y for cyclic dependency
class Y;
class X
{
Y *m_y;
...
};
/* ====== y.h ====== */
// Forward declaration of X for cyclic dependency
class X;
class Y
{
X *m_x;
...
};