dynamic_cast
conversion
クラスのポインタと参照を、継承階層に沿って上方、下方、および横方向に安全に変換します。
目次 |
、
、
構文
dynamic_cast<
target-type
>(
expression
)
|
|||||||||
| target-type | - | 完全なクラス型へのポインタ、完全なクラス型への参照、または(オプションでcv修飾された) void へのポインタ |
| expression | - | lvalue (C++11まで) glvalue (C++11以降) ( target-type が参照の場合は完全なクラス型のlvalue、 target-type がポインタの場合は完全なクラス型へのポインタのprvalue) |
説明
記述の便宜上、「
expression
または結果が
T
への参照である」とは、「それが型
T
のglvalueである」ことを意味する
(この表記は
decltype
の慣例に従う)
(C++11以降)
。
以下の変換のみが dynamic_cast によって実行可能です。ただし、そのような変換が const性の除去 (またはvolatile性の除去)となる場合は除きます。
Base
へのポインタ」であり、
expression
の型が「(cv修飾可能性のある)
Derived
へのポインタ」であり、
Base
が
Derived
の基底クラスである場合、結果は以下のいずれかとなる:
- expression がnullポインタ値の場合、nullポインタ値、または
-
それ以外の場合、
expression
が指す
Derivedオブジェクト内の唯一のBaseサブオブジェクト へのポインタ。言い換えれば、 dynamic_cast はポインタの アップキャスト (派生クラスから基底クラスへの変換)に使用できる。暗黙変換および static_cast もこの変換を実行可能である。
Base
への参照」であり、
expression
の型が「(cv修飾可能性のある)
Derived
」であり、
Base
が
Derived
の基底クラスである場合、結果は
expression
によって参照される
Derived
オブジェクト内の一意の
Base
サブオブジェクトである。言い換えれば、
dynamic_cast
は参照の
upcast
(派生クラスから基底クラスへの変換)に使用できる。暗黙変換および
static_cast
もこの変換を実行できる。
Target
に変換可能かどうかが確認されます:
Target
オブジェクトの公開基底クラスの部分オブジェクトであり、かつ
expression
が指す/参照する部分オブジェクトから派生した
Target
型のオブジェクトがただ一つである場合、結果はその
Target
オブジェクトを指す/参照します。言い換えれば、
dynamic_cast
は基底クラスから派生クラスへのポインタ/参照の
ダウンキャスト
に使用できます。
Target
の明確でpublicな基底クラスを持つ場合、結果は最も派生したオブジェクトの
Target
部分オブジェクトを指す/参照する。言い換えれば、
dynamic_cast
は同じ基底クラスから派生した2つの型間でポインタ/参照の
crosscast
(またはside-cast)に使用できる。
- target-type がポインタ型の場合、結果は target-type のヌルポインタ値となる。
- target-type が参照型の場合、 std::bad_cast 型の ハンドラ にマッチする型の例外がスローされる。
コンストラクタまたはデストラクタ内(直接的または間接的に) dynamic_cast が使用され、 expression が現在構築中/破棄中のオブジェクトを参照する場合、そのオブジェクトは最も派生したオブジェクトと見なされます。 target-type がコンストラクタ/デストラクタ自身のクラスまたはその基底クラスへのポインタまたは参照でない場合、動作は未定義です。
他のキャスト式と同様に、結果は以下の通りです:
|
(C++11まで) |
|
(C++11以降) |
注記
ダウンキャストは
static_cast
でも実行可能ですが、ランタイムチェックのコストを回避できる一方、プログラムが(他のロジックを通じて)
expression
が指すオブジェクトが確実に
Derived
であることを保証できる場合にのみ安全です。
一部の形式の dynamic_cast は run-time type identification (RTTI)、すなわちコンパイルされたプログラム内の各ポリモーフィッククラスに関する情報に依存しています。コンパイラは通常、この情報の組み込みを無効にするオプションを備えています。
キーワード
例
#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); // 適切に定義: 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は使用可能だが不要 [[maybe_unused]] D& new_d = dynamic_cast<D&>(a); // ダウンキャスト [[maybe_unused]] B& new_b = dynamic_cast<B&>(a); // サイドキャスト Base* b1 = new Base; if (Derived* d = dynamic_cast<Derived*>(b1); d != nullptr) { std::cout << "b1からdへのダウンキャスト成功\n"; d->name(); // 安全に呼び出し可能 } Base* b2 = new Derived; if (Derived* d = dynamic_cast<Derived*>(b2); d != nullptr) { std::cout << "b2からdへのダウンキャスト成功\n"; d->name(); // 安全に呼び出し可能 } delete b1; delete b2; }
出力:
downcast from b2 to d successful
不具合報告
以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| CWG 1269 | C++11 |
target-type
が右辺値参照型の場合、xvalue
expression に対してランタイムチェックが実行されなかった |
実行される |
| CWG 2861 | C++98 | expression が型アクセス不可能なオブジェクトを指す/参照する可能性があった | この場合の動作は未定義 |
参考文献
- C++23規格 (ISO/IEC 14882:2024):
-
- 7.6.1.7 動的キャスト [expr.dynamic.cast]
- C++20 標準 (ISO/IEC 14882:2020):
-
- 7.6.1.6 動的キャスト [expr.dynamic.cast]
- C++17規格 (ISO/IEC 14882:2017):
-
- 8.2.7 動的キャスト [expr.dynamic.cast]
- C++14 標準 (ISO/IEC 14882:2014):
-
- 5.2.7 動的キャスト [expr.dynamic.cast]
- C++11標準 (ISO/IEC 14882:2011):
-
- 5.2.7 動的キャスト [expr.dynamic.cast]
- C++98標準 (ISO/IEC 14882:1998):
-
- 5.2.7 動的キャスト [expr.dynamic.cast]
- C++03標準 (ISO/IEC 14882:2003):
-
- 5.2.7 動的キャスト [expr.dynamic.cast]