Любая хорошая причина для заголовочного файла C ++, чтобы не включать любые другие заголовочные файлы? - PullRequest
6 голосов
/ 04 августа 2011

Я видел такой стиль включения заголовка, где файлы заголовков не включают другие файлы заголовков, а соответствующие файлы * .cpp должны включать все зависимости (и включать их в правильном порядке).Возможно, в старые добрые времена это могло облегчить отслеживание зависимостей сборки (но я просто догадываюсь).Есть ли для этого веские причины?

Файл "Bh":

#ifndef _B_h_
#define _B_h_

// Note we do not #include "A.h" that contains class A declaration.

class B
{
public:
   A a; // An A object.
};
#endif // _B_h_

Файл "B.cpp":

#include "A.h" // Must include this before B.h, otherwise class A not defined in B.h
#include "B.h"

...

Ответы [ 6 ]

8 голосов
/ 04 августа 2011

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

5 голосов
/ 04 августа 2011

Кажется, кто бы ни написал этот код, он неправильно понял общую рекомендацию о сокращении количества включенных заголовков.Обычно рекомендуется удалить директивы ненужные #include <> в надежде ускорить компиляцию.Действительно, в больших проектах это может значительно ускорить компиляцию за счет:

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

В общем, люди будут рекомендовать (он был на стандартах кодирования для всех проектов, над которыми я работал), использовать предварительные объявления для классов, кроме классав соответствующем заголовке определено:

  1. , используемый в качестве базового класса;
  2. , используемый в качестве элемента данных;
  3. имеет неполную официальную спецификацию (например, контейнеры стандартной библиотекиразрешено иметь дополнительные аргументы шаблона до тех пор, пока они имеют значения по умолчанию, поэтому нестандартно объявлять их вперед).

В случаях 1 и 2 директива #include <> must появляются перед определением класса в всех зависимых исходных файлах и заголовках.По сути, он просто перемещает директиву (ы) #include <> из заголовка в каждую из своих зависимостей.Это приводит к большему количеству кода и делает это без пользы (например, время компиляции и т. Д. Будет одинаковым).По этой причине эта рекомендация также сопровождается другой записью в стандарте кодирования: каждый заголовочный файл должен компилироваться «автономно» (например, включаться в первую строку исходного файла).

4 голосов
/ 04 августа 2011

Это действительно плохая практика.Пусть компилятор определит правильный порядок - он менее подвержен ошибкам.Заголовки должны компилироваться так, как если бы они были включены самостоятельно, т. Е. Если у вас был TU, состоящий всего из #include "B.h".

2 голосов
/ 04 августа 2011

Я бы посчитал этот плохой стиль.Это приведет к непониманию ошибок.

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

2 голосов
/ 04 августа 2011

Да, я бы порекомендовал #include 'любая зависимость ИНТЕРФЕЙСА в любом заголовке.

В этом случае да: я бы #include "A" (потому что интерфейс B зависит от A).

В противном случае, если в реализации используется «A» (но в заголовке нет), я бы только #include A в .cpp (потому что это не часть интерфейса).

Под NOЯ бы хотел, чтобы обстоятельства заголовков имели значение, если их вообще можно было избежать.Как правило, порядок заголовков НЕ ДОЛЖЕН иметь значения.

ИМХО ...

PS: Как бы ни хотел Бьярн Страуструп, макросы препроцессора и препроцессора все еще очень важны для нас.Конечно, в C-Land, и, конечно, практически в любом Microsoft API.Это просто хорошая форма уважать этот факт.

2 голосов
/ 04 августа 2011

Есть ли для этого сегодня веская причина?

Нет, не совсем. Люди делают разные вещи, которые «будут работать», потому что они не знают ничего лучше, не заботятся или имеют более важные вещи, о которых нужно беспокоиться. Это происходит, когда ваш язык опирается на препроцессор, а не на настоящую систему импорта модулей.

Я бы сказал, что лучше всего убедиться, что человеку, включая ваши вещи, никогда не придется беспокоиться о порядке включений или скрытых предварительных условий. Если, конечно, ваша рука не навязана глупыми трюками с макросами, в любом случае.

...