私の C++ プロジェクトでは、いつ#include "myclass.h"
ヘッダー ファイルのインクルード ( ) を使用する必要がありますか? また、いつクラス ( class CMyClass;
) の前方宣言を使用する必要がありますか?
5 に答える
原則として、最初に前方宣言を試してください。これにより、コンパイル時間などが短縮されます。コンパイルされない場合は、を選択して#include
ください。次のいずれかを行う必要がある場合は、#includeを選択する必要があります。
- クラスのメンバーまたは機能にアクセスします。
- ポインタ演算を使用します。
- sizeofを使用します。
- RTTI情報。
new
/delete
、コピーなど。- 値で使用してください。
- それから継承します。
- メンバーとして持ってください。
- 関数内のインスタンス。
(@Mooing Duckからの6,7,8,9)
彼らはおそらくもっと多いですが、私は今日私の言語法の帽子をかぶっていません。
クラスへのポインタのみが必要であり、クラスの名前ではなくクラスに関する知識が必要ない場合は、前方宣言を使用できます。
宣言を転送するにはいくつかの問題があります。
- クラス名を複数の場所に保存するようなものです。ある場所で変更すると、他の場所でも変更する必要があります。コードは変更されたクラス名で正常にコンパイルされるため、リファクタリングは困難になりますが、前方宣言が未定義のクラスを参照するため、リンクは失敗します。ヘッダー ファイルをインクルードし、前方宣言を使用しない場合、コンパイル中にこれらの問題が発生します。
前方宣言は、他の人が維持するのが困難です。たとえば、ヘッダー ファイルに以下が含まれているとします。
include "MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h"
前方宣言ではなく
class Foo ;
クラス Foo が宣言されている場所を他の人が簡単に見つけることができます。前方宣言では、それほど明白ではありません。Eclipse などの一部の IDE では、ユーザーが変数の宣言を開こうとすると、前方宣言を開くことがあります。
- 前方宣言を含むヘッダー ファイルをコードに含めるが、実際のコード定義がリンクしていない他のライブラリにある場合、未定義のシンボル エラーでリンクが失敗することがあります。コンパイル時にこの問題を次のようなエラーでキャッチする方が便利
"Could not find file MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h"
です。それ以降、対応するものを探して、それFoo.cpp
を含むライブラリを特定する場所がわかります。
ビルドに時間がかかりすぎると思われる場合は、リンクなしでコンパイルのみを実行してみてください。コードのコンパイルに 10 秒、リンクに 10 分かかる場合、問題はいくつかの余分なインクルードとは関係ありません。同様に、ヘッダー ファイルに非常に多くの内容が含まれているため、実際にパフォーマンスの問題が発生している場合は、おそらく、そのファイルの内容を複数の小さなヘッダー ファイルにリファクタリングする必要があります。
では、いつ前方宣言してもよいのでしょうか? 実際の宣言と同じヘッダーファイルで行う場合。
例:
class Foo ;
typedef Foo* FooPtr ;
typedef Foo& FooRef ;
class Foo
{
public:
Foo( ) ;
~Foo( ) ;
}
また
class TreeNode ;
class Tree
{
private:
TreeNode m_root ;
}
class TreeNode
{
void* m_data ;
} ;
初心者として、ヘッダー ファイルに含まれる型や関数を使用する必要がある場合は、常にヘッダー ファイルを #include する必要があります。前方宣言によってビルドを「最適化」しようとしないでください。大規模なプロジェクトであっても、プロジェクトはよく設計されています。
絶対に前方宣言が必要になるのは、次のような状況だけです。
struct A {
void f( B b );
};
struct B {
void f( A a );
};
各構造体 (またはクラス) は、他の型を参照します。この場合、問題を解決するには B の前方宣言が必要です。
struct B; // forward declaration
struct A {
void f( B b );
};
struct B {
void f( A a );
};
#include
コンパイル時間を短縮するためだけでなく、モジュール性とテスト容易性を高めるためにも、 を最小限に抑えるよう努める必要があります。@ypnos が言うように、ポインタだけが必要な場合、クラス転送は優れています。
ヘッダーの依存関係を減らす方法に関するいくつかの実用的なヒントについては、たとえば、この記事を参照してください。