Чтобы убедиться, что заголовочные файлы включают в себя все, что им нужно, я бы создал исходный файл, который все, что он делает, это включил заголовочный файл и попытался скомпилировать его. Если компиляция не удалась, в самом файле заголовка отсутствует файл include.
Тот же эффект можно получить, применив следующее правило: первый файл заголовка, который должен включать foo .c или foo .cpp, должен иметь соответственно имя Foo .h.
Это гарантирует, что foo .h включает все, что нужно для компиляции.
Кроме того, в книге Лакоса Крупномасштабный программный дизайн C ++ (например) перечислено много, много методов для перемещения деталей реализации из заголовка в соответствующий файл CPP. Если вы возьмете это до крайности, используя такие методы, как Cheshire Cat (который скрывает все детали реализации) и Factory (который скрывает существование подклассов), тогда многие заголовки смогут стоять в одиночестве, не включая другие заголовки, а вместо этого обходятся только вместо этого переадресуйте объявление непрозрачным типам ... за исключением, возможно, шаблонных классов.
В конце каждый заголовочный файл может содержать:
Нет файлов заголовков для типов, которые являются элементами данных (вместо этого элементы данных определяются / скрываются в файле CPP с использованием метода "cheshire cat" a.k.a. "pimpl")
Нет заголовочных файлов для типов, которые являются параметрами или возвращают типы из методов (вместо этого это предопределенные типы, такие как int
; или, если они являются пользовательскими типами, то это ссылки, в которых если достаточно заранее объявленного, непрозрачного объявления типа, такого как просто class Foo;
вместо #include "foo.h"
в заголовочном файле).
Тогда вам нужен заголовочный файл для:
Суперкласс, если это подкласс
Возможно, любые шаблонные типы, которые используются в качестве параметров метода и / или возвращаемых типов: очевидно, вы должны быть в состоянии также заранее объявить классы шаблона, но некоторые реализации компилятора могут иметь проблемы с этим (хотя Вы также можете инкапсулировать любые шаблоны, например List<X>
, в качестве подробностей реализации пользовательского типа, например ListX
).
На практике я мог бы создать "standard.h", который включает все системные файлы (например, заголовки STL, специфичные для O / S типы и / или любые #define
s и т. Д.), Которые используются любыми / всеми файлы заголовков в проекте, и включите их в качестве первого заголовка в каждый файл заголовка приложения (и скажите компилятору, что этот «standard.h» следует рассматривать как «предварительно скомпилированный файл заголовка»).
//contents of foo.h
#ifndef INC_FOO_H //or #pragma once
#define INC_FOO_H
#include "standard.h"
class Foo
{
public: //methods
... Foo-specific methods here ...
private: //data
struct Impl;
Impl* m_impl;
};
#endif//INC_FOO_H
//contents of foo.cpp
#include "foo.h"
#include "bar.h"
Foo::Foo()
{
m_impl = new Impl();
}
struct Foo::Impl
{
Bar m_bar;
... etc ...
};
... etc ...