Включая #includes в заголовочном файле по сравнению с исходным файлом

Мне нравится помещать весь мой #includes в мой заголовочный файл затем, только включают мой заголовок для того исходного файла в моем исходном файле. Каков промышленный стандарт? Есть ли, кто-либо тянет спины к моему методу?

49
задан Duncan Jones 12 July 2018 в 22:25
поделиться

1 ответ

Как правило, вы хотите поместить в файл заголовка класса только минимум необходимых включений, так как любой, кто использует этот заголовок, будет вынужден #include их все. В более крупных проектах это приводит к более медленным сборкам, проблемам с зависимостями и всевозможным неприятностям.

Думайте о файле заголовка как о публичном интерфейсе вашего класса. Вы не хотите обременять всех, кто его использует, дополнительными зависимостями, если только они не необходимы , чтобы иметь возможность использовать класс.

Переместите все, что требуется только в реализации класса, в исходный файл. Для других классов, используемых в заголовке, только #include их заголовки, если вам действительно нужно знать их размер или содержимое в заголовке - все остальное и предварительное объявление ] достаточно. В большинстве случаев вам нужно только #include классов, от которых вы наследуете, и классов, объекты которых являются членами-значениями вашего класса.

Эта страница содержит хорошее резюме. (Реплицируется ниже для справки)


Заголовочный файл C ++ включает шаблоны #

Большие программные проекты требуют тщательного управления заголовочными файлами даже при программировании на 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 - это базовый класс, поэтому объявление класса требуется для завершения объявления класса. Компилятору необходимо знать размер ABase , чтобы определить общий размер A . В этом случае abase.h следует явно включить в a.h .
  • Класс B: Класс A содержит класс B по значению, поэтому объявление класса требуется для завершения объявления класса. Компилятору необходимо знать размер B, чтобы определить общий размер A . В этом случае b.h следует явно включить в a.h .
  • Класс C : Класс C включен только в качестве ссылки на указатель. Размер или фактическое содержимое C не важны для a.h или a.cpp . Таким образом, в a.h было включено только предварительное объявление. Обратите внимание, что c.h не был включен ни в a.h , ни в a.cpp .
  • Класс D : Класс 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;
    ...
};
65
ответ дан 7 November 2019 в 11:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: