階層の下位または全体にキャストする場合、階層に多相性がなければなりません (仮想関数を持つ必要がある)。結果は実行時に検証されます。
階層の下位または全体にキャストする場合、v から T に変換できないことがあります。たとえば、試行された変換があいまいであったり、T に対するアクセスが不可能であったり、あるいは必要な型のオブジェクトを v が指さない (あるいは参照しない) 場合がこれに当たります。実行時検査が失敗し、T がポインタ型である場合、キャスト式の値は型 T のヌルポインタです。T が参照型の場合、何も返されず (C++ にはヌル参照は存在しない)、標準例外 std::bad_cast が送出されます。
class A { public: virtual void f( ); };
class B { public: virtual void g( ); };
class AB : public virtual A, private B { };
void simple_dynamic_casts( )
{ AB ab;
B* bp = (B*)&ab; // 限定公開の壁を破るためキャストが必要
A* ap = &ab; // 公開派生のためキャスト不要
AB& abr = dynamic_cast<AB&>(*bp); // 成功
ap = dynamic_cast<A*>(bp); assert( ap != NULL );
bp = dynamic_cast<B*>(ap); assert( bp == NULL );
ap = dynamic_cast<A*>(&abr); assert( ap != NULL );
bp = dynamic_cast<B*>(&abr); assert( bp == NULL ); }
1 つの基底クラスについて仮想継承と多重継承が存在する場合には、実際の動的キャストは一意の照合を識別することができなければなりません。もし照合が一意でないならば、そのキャストは失敗します。たとえば、下記の追加クラス定義が与えられた場合、
class AB_B : public AB, public B { };
class AB_B__AB : public AB_B, public AB { };
void complex_dynamic_casts( )
{
AB_B__AB ab_b__ab;
A*ap = &ab_b__ab;
// OK: A を静的に特定できる
AB*abp = dynamic_cast<AB*>(ap);
// 失敗: あいまい
assert( abp == NULL );
// 静的エラー: AB_B* ab_bp = (AB_B*)ap;
// 動的キャストではない
AB_B*ab_bp = dynamic_cast<AB_B*>(ap);
// 動的キャストは成功
assert( ab_bp != NULL );
}
dynamic_cast のエラー時のヌル (NULL) ポインタの戻り値は、コード中の 2 つのブロック (1 つは型推定が正しい場合にキャストを処理するためのもの、もう 1 つは正しくない場合のもの) の間の条件として役立ちます。
void using_dynamic_cast( A* ap )
{
if ( AB *abp = dynamic_cast<AB*>(ap) )
{ // abp は NULL でないので
// ap は AB オブジェクトへのポインタ。
// abp を使用する。
process_AB( abp ); }
else
{ // abp は null。
// したがって ap は AB オブジェクトへのポインタではない。
// abp は使用しない。
process_not_AB( ap );
}
互換モード (-compat=4) では、-features=rtti コンパイラオプションによって実行時の型情報が有効になっていないと、コンパイラは dynamic_cast を static_cast に変換し、警告メッセージを出します (第 5 章「例外処理」を参照)。
実行時型情報が無効にされている場合、すなわち -features=no%rtti の場合には 、コンパイラは dynamic_cast を static_cast に変換し、警告を発します (第 6 章「実行時の型識別」を参照)。
動的キャストは必然的に、仮想関数による変換のような適切な設計パターンより遅くなります。Erich Gamma 著 (ソフトバンク)『オブジェクト指向における再利用のためのデザインパターン』を参照してください。