web-dev-qa-db-ja.com

ヘッダーファイルに含めるか、フォワード宣言に含め、.cppに含める

クラスBがあり、クラスAのメンバーを呼び出したいので、

1。

//A.h    
class B; 
class A 
{ 
private:
    B* m_p; 
}; 

//a.cpp
#include "B.h"

2。

// A.h
#include "B.h"

class A 
{ 
private: 
    B * impl_; 
}; 

どちらの方法が優れているか、依存関係があまりない小さなプロジェクトが関係する場合、この2つは似ていますか?

31
colddie

それを行う最初の方法は、a.hclass B存在はわかっているが、その定義。これにより、a.h内でBを使用して実行できることが制限されます。たとえば、タイプB *の変数は使用できますが、タイプBの変数は使用できません(タイプBの変数の宣言の場合、コンパイラはコンパイラを参照できる必要があるため) Bの完全な定義)。また、B *型の変数がある場合、ポインターを逆参照することはできません(そのためにも、Bの定義がわかっている必要があるため)。

したがって、これらの問題のない2番目の選択肢が推奨され、ほとんどの人がこれを使用します。

これは、最初の方法が役立つ特殊なケースにすぎません。例えば:

  • .hファイルに他のが含まれている場合(ただし、インクルードガードに関しても、さらに多くの問題が発生する可能性があります。これは通常、難しく、避けるべきです);
  • b.hが非常に大きく複雑な場合、コンパイルプロセスの速度が低下するため、可能な限り含めないでください。
32
jogojapan

最初の方法は、前方宣言です。 2番目には実際にクラスBが含まれています。

どちらを使用するのですか?

最初のものは次の場合に使用します。

  • Aのdefinitionでは、Bへのポインタのみがあり、Bのメンバーはありません。
  • AのdefinitionからBの関数を呼び出すことはありません(つまり、Bのメンバー関数へのすべての呼び出しは、Aのメンバー関数を実際に実装する.cppファイルで行われます)。
  • クラスBのインターフェイスまたはサイズは頻繁に変更されるが、Aのインターフェイスは変更されないことを期待します。これにより、Bが変更された場合、a.cppのコンテンツのみが再コンパイルされますが、ah(およびahを含む他のファイル)は変更する必要がありません。 。

2つ目は次の場合に使用します。

  • Bのsizeを知っている必要があります。コンパイラは、クラス定義とそのすべてのメンバーのサイズを使用して、クラスのサイズを計算します。たとえば、クラスAにタイプBのメンバーがある場合、Aのサイズを計算するには、コンパイラーがBのサイズを知っている必要があります。 Bのサイズを知るには、b.hを含める必要があります。
    • クラスBの関数を呼び出す必要があります。実際に存在する関数を呼び出しているかどうかを知るには、コンパイラーがクラスBのインターフェースを知っている必要があります。つまり、b.hを含める必要があります。
17
maditya

回答:1
ご覧ください http://www.umich.edu/~eecs381/handouts/handouts.html

Cヘッダーファイルのガイドライン

C++ヘッダーファイルガイドライン (ミシガン大学EECS部、David Kieras著)は次のように述べています。

ガイドライン#10。 X型の宣言が不完全な場合は、ヘッダーを含む#.hの代わりにそれを使用してください。別の構造体またはクラス型Xがヘッダーファイルのコンテンツでポインターまたは参照型としてのみ表示される場合は、#include Xhではなく、Xの不完全な宣言(「前方」宣言とも呼ばれる)をヘッダーファイルの先頭。例:class X;この強力で価値のある手法の詳細については、配布資料 不完全な宣言 を参照してください。標準ライブラリには、<iostream>という名前の<iosfwd>ライブラリによく使用される不完全な宣言のヘッダーが含まれていることに注意してください。 #include <iosfwd><iostream>ヘッダーファイルは非常に大きい(巨大なテンプレート!)ため、可能な場合はいつでも使用できます。

11
Andrey Volk

クラスAのヘッダーでクラスを宣言するだけです。

class B;
0
Steve Seo

2番目の方が優れています。 Bクラスを、.hファイルを使用してインクルードするモジュールにします。将来的にBをサブクラス化し、Aを使用してCを使用するように更新する場合を考えます。 2番目のケースでは、ヘッダー#includeおよびAのメイクアップのみを置き換えます。最初のケースでは、フォワード宣言を変更する必要があります。また、2番目のケースでは、シンボルB以外のものも定義します。

そして、コメントのように、ヘッダーファイルが残りのコードと同じディレクトリにある場合は、#include "B.h"を使用する必要があります。

0

さて、あなたがしていることは前方デクレレーションと呼ばれます、あなたが望む理由は、クラスBを使用するクラスAとクラスAを使用するALSOクラスBのようなものがある場合です。

リレーションが1つしかない場合は、2番目の選択肢を使用できます。二重使用が必要な場合は、クラスdeclerationの少なくとも1つが前方declerationを使用する必要があります

0
Alon