C++とObjective-Cでは、ヘッダーに定義する必要のないクラスを前方宣言し、必要に応じてこれらのクラスを定義するヘッダーファイルをソースファイルにインポートするという習慣に慣れてきました。フォワード宣言の短所?
これは良い考えではない状況がありますか?
(前方宣言の大きな欠点は、不完全な型の使い勝手が限られていることです。この質問の目的のためには、前方宣言されたクラスを不完全型として使用する必要があると仮定します)。
C++とObjective-Cでは、ヘッダーに定義する必要のないクラスを前方宣言し、必要に応じてこれらのクラスを定義するヘッダーファイルをソースファイルにインポートするという習慣に慣れてきました。フォワード宣言の短所?
これは良い考えではない状況がありますか?
(前方宣言の大きな欠点は、不完全な型の使い勝手が限られていることです。この質問の目的のためには、前方宣言されたクラスを不完全型として使用する必要があると仮定します)。
時々、あなたはすべてのエラー
class Foo;
template < typename T>
struct Trait
{
static const int MY_TYPE = -1;
};
// Lets say this is Foo.h
//class Foo
//{
//};
//template<>
//struct Trait<Foo>
//{
// static const int MY_TYPE = 1;
//};
void TestFunction(Foo& f)
{
std::cout << Trait<Foo>::MY_TYPE << std::endl;
}
を上昇させずに微妙プログラムのセマンティクスを変更することができますが、上記のコードを検討し、コメントアウトコードは、ヘッダーに住んでいます。ヘッダが含まれている場合はTestFunctionは、そうでない場合は1を出力します-1
1つの欠点は、情報の隠蔽/カプセル化がないことです。
できるだけ最小限のヘッダーファイルを作成することをお勧めします。それは、私が非常に多くの機能をサポートし続ける義務はないということです。私が何かを変更したいと思っていて、公開ヘッダーに公開されていないものがあれば、他の誰かに影響を与えることなくクラスの内部で変更することができます。
EDIT:
ルークはそうここ屋に行く、例えば尋ねた:
あなたはCar
というクラスがあるとします。あなたが作成した唯一のものは、ポイントAからポイントBに移動することでした。個人的に、私はヘッダファイルをCar
というクラスとDrive
というメソッドに保つことを好みます。あなたの質問(「私ができるすべてのクラス」)を表現した方法から、私は「DieselEngine」、「PetrolEngine」、「HybidEngine」などのクラスをヘッダーファイルにも見つけることが期待されます。この問題は、プロジェクトに取り組んでいる他の人々(または、時間の経過とともに)が公開されたクラスを使用し始めることです。 2年後、PetrolEngineクラスが実際に私に問題を引き起こしていると判断しました。私はそれを取り除き、それをHybridEngineと完全に置き換えたと思います.-まあ、今PetrolEngineあなたが理解していない理由のために100の他のファイルに封じ込められています。そして今、PetrolEngineを使用している他のすべての人のためにPetrolEngineを(そして以前と同じように)使い続けることを余儀なくされています。あなたがそのクラスを最初にどのように使用したかったのかのための堅実な「契約」を持っていなかったからです。それはあなたが実際に成したがっていること、車を作ることの実装の詳細でした。情報隠蔽についてのコメントを議論する
EDIT:
あなたがやっているすべては、厳密には、クラス/構造体名をフォワード宣言されている場合は - まあ、私は、「なぜ」を再度求めるだろうと思います。ヘッダーファイルとクラスのコンシューマーで、そのクラスで実際に何もできません。また、プリンシパルクラスのAPIのパラメータまたは戻り値の型として公開されていない場合は、なぜそれをすべて公開するのですか?
コンパイル時に、不透明なデータ構造の安全性チェックに使用している場合は、これが1つのことです。しかし、あなたの質問を表現する方法は私にはすべてのように聞こえましたはもちろん、ヘッダーファイルに入った。
私はあなたが何を意味するか分かりません。例を挙げていただけますか? – Luke
この方法は情報隠蔽を強化しませんか?前方宣言には、完全宣言よりもずっと少ない情報があります。 –
フォワード宣言がどのようにカプセル化を破るか説明できますか?クラス名だけを指定すると、完全な定義を提供するよりもはるかに多くの情報が隠されているように思えます。 –
私が知る限りはありません。すでに説明した唯一の欠点は、不完全な型を使用することです。あなたは完全に定義された型を必要とする用途がないと言うので、あなたは大丈夫です。
ヘッダーにクラスの定義全体を必要としない場合は、完全なファイルの組み込みより前方の宣言が優先されます。私が考えることができる唯一の不利な点は、@Stephen Darlingtonのコメントとして既に投稿されています。 :)
欠点の1つは、フォワード宣言された型の潜在的なメモリリークです。詳細はthis questionを参照してください。この場合、マイクロソフトのコンパイラはwarning C4150: deletion of pointer to incomplete type 'SomeType'; no destructor called
を発行します。クラス、関数、グローバル変数/定数(extern
を使用)、C++ 11、列挙型で:
実際のコンパイラでは問題ありません。 –
前方宣言は、多くのものに適用することができます。
主な欠点は、私の知る限り見ることができるように、冗長性がエラーのためのより多くの範囲を紹介するので、しかし、これはあなたが前方に宣言されているものに応じて非常に異なっ適用、冗長です。
あなたはクラスの前方宣言、グローバルまたは列挙型との誤差を持っている場合、コンパイラは(ええ!)それを拾う必要があります。あなたは、関数の宣言でエラーが発生している場合は
は、その後、Cには、単にオーバーロードを作成しました++(oups!)。
私はそのためのクラス、グローバルまたは列挙型を宣言して転送する本当の欠点がないことを言うだろう。しかし、関数については、#include
に固執すれば、関連する関数をグループ化したヘッダーを作成して、あまりにも多くのファイルを作成することを避けることができます。
をそれは主に、おそらくあなたのコーディング作業を継続する必要がありますあなたの同僚のための読みやすさの問題です。
フルビルド中にコーヒーを飲む機会が減りますか? –