私はすべての#includeをヘッダーファイルに入れてから、そのソースファイルのヘッダーのみをソースファイルに含めるようにします。業界標準とは何ですか?メソッドに欠点はありますか?
一般に、必要な最小限のインクルードのみをクラスヘッダーファイルに配置する必要があります。そのヘッダーを使用する他のユーザーは、それらもすべて#include
に強制されます。大規模なプロジェクトでは、これによりビルドが遅くなり、依存関係の問題が発生し、その他のあらゆる厄介な問題が発生します。
ヘッダーファイルは、クラスへのパブリックインターフェイスと考えてください。クラスを使用できるようにするためにnecessaryでない限り、それを使用するすべての人を余分な依存関係でsしたくありません。
クラス実装でのみ必要なものはすべてソースファイルに移動します。ヘッダーで使用される他のクラスの場合、ヘッダーのサイズまたは内容を実際に知る必要がある場合は、ヘッダーのみ#include
を使用します-その他および 前方宣言 で十分です。ほとんどの場合、#include
継承元のクラス、およびオブジェクトがクラスの値メンバーであるクラスのみが必要です。
このページ には要約があります。 (参照用に以下に複製)
大規模なソフトウェアプロジェクトでは、Cでプログラミングする場合でも慎重なヘッダーファイル管理が必要です。開発者がC++に移行すると、ヘッダーファイル管理はさらに複雑で時間がかかります。ここでは、この雑用を簡素化するヘッダーファイルの包含パターンをいくつか示します。
ここでは、ヘッダーファイルの管理を簡素化するために必要なC++ヘッダーファイルを含める基本的なルールについて説明します。
ヘッダーファイルは、前方宣言がジョブを実行しない場合にのみ含める必要があります。ヘッダーファイルは、ヘッダーファイルを含める順序が重要ではないように設計する必要があります。これは、x.h
がx.cpp
の最初のヘッダーファイルであることを確認することで実現されます。ヘッダーファイルのインクルードメカニズムは、ヘッダーファイルのインクルードの複製を許容する必要があります。次のセクションでは、例を使用してこれらの規則について説明します。
次の例は、さまざまなタイプの依存関係を示しています。 a.cpp
およびa.h
にコードが格納されているクラスAを想定します。
a.h
#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
が含まれているため、クラス宣言を完了するにはクラス宣言が必要です。コンパイラは、A
の合計サイズを決定するためにBのサイズを知る必要があります。この場合、b.h
をa.h
に明示的に含める必要があります。Class C
は、ポインター参照としてのみ含まれています。 C
のサイズまたは実際のコンテンツは、a.h
またはa.cpp
にとって重要ではありません。したがって、a.h
には前方宣言のみが含まれています。 c.h
はa.h
またはa.cpp
のいずれにも含まれていません。D
は、a.h
のポインター参照としてのみ使用されます。したがって、前方宣言で十分です。ただし、a.cpp
は実質的にクラスD
を使用するため、d.h
を明示的に含めます。ヘッダーファイルは、前方宣言がジョブを実行しない場合にのみ含める必要があります。 c.h
とd.h
を含めないことにより、クラスA
の他のクライアントは、値でクラスCとDを使用しない限り、c.h
とd.h
を心配する必要はありません。 a.h
は、a.cpp
の最初のヘッダーファイルとして含まれています。これにより、a.h
は、a.h
の前に特定のヘッダーファイルが含まれることを期待しません。 a.h
が最初のファイルとして含まれているので、a.cpp
のコンパイルが成功すると、a.h
はa.h
の前に他のヘッダーファイルが含まれることはありません。すべてのクラスでこれに従う場合(つまり、x.cpp
には常に最初のヘッダーとしてx.h
が含まれます)、ヘッダーファイルのインクルードに依存しません。 a.h
には、シンボル_a_h_included_
のプリプロセッサ定義のチェックが含まれます。これにより、a.h
の包含の複製が許容されます。
次の例では、クラスX
とY
の間に循環依存関係が存在します。この依存関係は、前方宣言を使用して処理されます。
x.h and 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;
...
};