2
class CBase { };
class CDerived: public CBase { };

CBase     b; 
CBase*    pb;
CDerived  d; 
CDerived* pd;

pb = dynamic_cast<CBase*>(&d);     // ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b);  // wrong: base-to-derived

「ベースから派生」キャストが間違っていることは知っています。しかし、その内部の理由は何ですか?内部の論理的な理由は何ですか?これ以上の説明なしにこれを思い出すのは難しいと思います。ありがとう!

4

4 に答える 4

6

まず、ここCBaseで使用するには多相的でなければなりませんdynamic_cast(つまり、少なくとも 1 つのvirtualメンバー関数が必要です)。それ以外の場合は使用できませんdynamic_cast

&bそうは言っても、 toのキャストはCDerived*間違っていません: pdnull ポインターになります。

dynamic_castキャストが失敗した場合 (つまり、ポインターが指すオブジェクトがターゲット型でない場合) に null ポインターを生成するという便利なプロパティがあります。これにより、オブジェクトの実際のタイプをテストできます。例えば:

CBase b;
CDerived d;

CBase* pb = &b;
CBase* pd = &d;

CDerived* xb = dynamic_cast<CDerived*>(pb); // xb is null!
CDerived* xd = dynamic_cast<CDerived*>(pd); // xd points to d!

を使用した場合、コードは正しくstatic_castありません。これは、実行時の型チェックを実行せずにキャストするためです。つまり、キャストが成功したかどうかをテストする方法がありません。クラス階層をキャストダウンする必要があり、オブジェクトがキャストしようとしている派生型であるかどうかが確実にわからない場合は、 を使用する必要がありますdynamic_cast

于 2011-03-16T04:18:59.950 に答える
2

派生から基底への変換では、キャストを明示的に指定する必要はありません (通常は必要ありません)。

CDerived d;
CBase *pb = &d;   // perfectly fine

基本から派生キャストへのキャストは、実際には間違っていませんが、一般的には避けたほうがよいでしょう。その背後にある理由は非常に単純です。ベースへのポインターは、実際のベース オブジェクトまたはそれから派生したものを指している可能性があります。このようにダウンキャストする場合は、通常、変換が成功したかどうかを確認する必要があります。指定した特定のケースでは成功しないため、割り当てられるもの (の結果dynamic_cast) は単に null ポインターになります。

ほとんどの場合、基本クラスのクラスのオブジェクトへの完全なインターフェイスを指定することを好むため、ダウンキャストが必要になることはめったにありません。

于 2011-03-16T04:20:09.370 に答える
1

派生クラスは、基本クラスよりも多くの「動作」を持つことができます。より多くのメンバー関数、より多くのメンバー データなど。基本クラスを派生クラスにキャストし、それを派生クラスとして扱おうとすると、できないことを実行させようとします。基本クラスのインスタンスに何かをさせようとしているため、派生クラスだけがその方法を知っています。

于 2011-03-16T04:18:59.283 に答える
0

pd型のポインタですCDerived*。そのため、pdポインティング オブジェクトには 2 つのサブオブジェクトが含まれている必要があります (つまり、 base と派生 )。しかし、この声明で -

pd = dynamic_cast<CDerived*>(&b);

ここで、pdはベース サブオブジェクトのみを指しています。サブオブジェクトを指す部分的な方法はありません。だから、それは間違っています。

于 2011-03-16T04:21:55.010 に答える