dynamic_cast 変換
提供: cppreference.com
継承階層に沿って上へ、下へ、および横へ、クラスへのポインタおよび参照を安全に変換します。
目次 |
[編集] 構文
dynamic_cast < new-type > ( expression )
|
|||||||||
new-type | - | 完全クラス型へのポインタ、完全クラス型への参照、または void (cv 修飾されていても構いません) へのポインタ。 |
expression | - | new-type が参照の場合は完全クラス型の lvalue (C++11未満)glvalue (C++11以上)、 new-type がポインタの場合は完全クラス型へのポインタの prvalue。 |
キャストが成功した場合、 dynamic_cast
は new-type 型の値を返します。 キャストが失敗し、 new-type がポインタ型の場合は、その型のヌルポインタを返します。 キャストが失敗し、 new-type が参照型の場合は、 std::bad_cast 型のハンドラにマッチする例外を投げます。
[編集] 説明
以下の変換のみが dynamic_cast を用いて行うことができます。 ただし cv 修飾を除去することはできません。
1) expression の型が new-type と正確に同じであるか、 new-type の cv 修飾がより少ないバージョンである場合、結果は new-type の型を持つ expression の値です (別の言い方をすると、 dynamic_cast は cv 修飾を追加することができます。 暗黙の変換および static_cast も同様にこの変換を行うことができます)。
2) expression の値がヌルポインタ値の場合、結果は new-type 型のヌルポインタ値です。
3) new-type が
Base
へのポインタまたは参照であり、 expression の型が Derived
へのポインタまたは参照であり、 Base
が Derived
の一意かつアクセス可能な基底である場合、結果は expression が指しているまたは表している Derived
オブジェクト内の Base
クラス部分オブジェクトへのポインタまたは参照です (ノート: 暗黙の変換および static_cast も同様にこの変換を行うことができます)。4) expression が多相型へのポインタで、 new-type が void へのポインタの場合、結果は expression が指しているまたは参照している最も派生したオブジェクトへのポインタです。
a) expression が指しているまたは表している最も派生したオブジェクトが調べられます。 そのオブジェクトにおいて、 expression が
Derived
のパブリックな基底を指しているまたは参照している場合、かつ、 expression が指しているまたは表している部分オブジェクトから派生した Derived
型のオブジェクトが唯一の場合、キャストの結果はその Derived
オブジェクトを指すまたは参照します (これは「ダウンキャスト」と言います)。b) そうでなく、 expression が最も派生したオブジェクトのパブリックな基底を指しているまたは参照しており、かつ、同時に、その最も派生したオブジェクトが曖昧でないパブリックな
Derived
型の基底クラスを持つ場合、キャストの結果はその Derived
を指すまたは参照します (これは「クロスキャスト」と言います)。c) そうでなければ、実行時のチェックは失敗します。 dynamic_cast がポインタに対して使用された場合は、 new-type 型のヌルポインタ値が返されます。 参照に対して使用された場合は、例外 std::bad_cast が投げられます。
6) dynamic_cast が (直接または間接的に) コンストラクタまたはデストラクタ内で使用され、 expression が現在構築中または破棄中のオブジェクトを参照しているときは、そのオブジェクトが最も派生したオブジェクトとみなされます。 new-type がそのコンストラクタまたはデストラクタの自分のクラスまたはその基底のいずれかへのポインタまたは参照でない場合、動作は未定義です。
他のキャスト式と同様に、
- new-type が左辺値参照型の場合、結果は lvalue です (expression は lvalue でなければなりません)。
- new-type が右辺値参照型の場合、結果は xvalue です (expression は lvalue でも rvalue でも構いません (C++17未満)完全クラス型の glvalue でなければなりません (prvalue は具体化されます) (C++17以上))。
- new-type がポインタ型の場合、結果は prvalue です。
[編集] ノート
- ダウンキャストは static_cast を用いても行うことができ、それによって実行時のチェックのコストを回避することができますが、これは expression の指すオブジェクトが間違いなく
Derived
であることを (他の何らかのロジックによって) 保証できる場合にのみ安全です。
- dynamic_cast の一部の形式は実行時型識別、つまり、コンパイルされたプログラム内の多相クラスに関する情報に依存しています。 一般的にコンパイラはこの情報を含めないようにするオプションを持っています。
[編集] キーワード
[編集] 例
Run this code
#include <iostream> struct V { virtual void f() {}; // 実行時チェック付きの dynamic_cast を使用するために // 多相でなければなりません。 }; struct A : virtual V {}; struct B : virtual V { B(V* v, A* a) { // 構築中のキャスト (下の D のコンストラクタ内の呼び出しを参照してください)。 dynamic_cast<B*>(v); // well-defined。 v は V* 型 で、 V は B の基底なので、結果は B* です。 dynamic_cast<B*>(a); // 未定義動作。 a は A* 型であり、 A は B の基底ではありません。 } }; struct D : A, B { D() : B(static_cast<A*>(this), this) { } }; struct Base { virtual ~Base() {} }; struct Derived: Base { virtual void name() {} }; int main() { D d; // 最も派生したオブジェクト。 A& a = d; // アップキャスト。 dynamic_cast を使っても構いませんが、必要はありません。 D& new_d = dynamic_cast<D&>(a); // ダウンキャスト。 B& new_b = dynamic_cast<B&>(a); // クロスキャスト。 Base* b1 = new Base; if(Derived* d = dynamic_cast<Derived*>(b1)) { std::cout << "downcast from b1 to d successful\n"; d->name(); // 呼んでも安全です。 } Base* b2 = new Derived; if(Derived* d = dynamic_cast<Derived*>(b2)) { std::cout << "downcast from b2 to d successful\n"; d->name(); // 呼んでも安全です。 } delete b1; delete b2; }
出力:
downcast from b2 to d successful