Namespaces
Variants

dynamic_cast conversion

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

クラスのポインタと参照を、継承階層に沿って上方、下方、および横方向に安全に変換します。

目次

翻訳の説明: - 「Contents」を「目次」に翻訳しました - HTMLタグ、属性、
タグ内のテキストは翻訳していません
- C++固有の用語(Syntax、Explanation、Notes、Keywords、Example、Defect reports、References、See also)は原文のまま保持しています
- 数値や構造は完全に保持されています
- フォーマットとリンクは変更していません

構文

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性の除去)となる場合は除きます。

1) expression の型が厳密に target-type であるか、または target-type のより少ないcv修飾バージョンである場合、結果は型 target-type を持つ expression の値となる。言い換えれば、 dynamic_cast const性の付加 に使用できる。暗黙変換および static_cast もこの変換を実行できる。
2) target-type が「(cv修飾可能性のある) Base へのポインタ」であり、 expression の型が「(cv修飾可能性のある) Derived へのポインタ」であり、 Base Derived の基底クラスである場合、結果は以下のいずれかとなる:
  • expression がnullポインタ値の場合、nullポインタ値、または
  • それ以外の場合、 expression が指す Derived オブジェクト内の唯一の Base サブオブジェクト へのポインタ。言い換えれば、 dynamic_cast はポインタの アップキャスト (派生クラスから基底クラスへの変換)に使用できる。暗黙変換および static_cast もこの変換を実行可能である。
3) target-type が「(cv修飾可能性のある) Base への参照」であり、 expression の型が「(cv修飾可能性のある) Derived 」であり、 Base Derived の基底クラスである場合、結果は expression によって参照される Derived オブジェクト内の一意の Base サブオブジェクトである。言い換えれば、 dynamic_cast は参照の upcast (派生クラスから基底クラスへの変換)に使用できる。暗黙変換および static_cast もこの変換を実行できる。
4) もし expression ポリモーフィック型 のヌルポインタ値である場合、結果は target-type のヌルポインタ値となります。
5) それ以外の場合、 expression はその 生存期間 内、または構築・破棄期間内にある ポリモーフィック型 のオブジェクトへのポインタまたは参照でなければならず、その型は expression の型と 類似 していなければならない(そうでない場合、動作は未定義である)
a) もし expression が(cv修飾された可能性のある) void へのポインタである場合、結果は expression が指す 最も派生したオブジェクト へのポインタとなります。
b) それ以外の場合、実行時チェックが適用され、 expression によって指される/参照されるオブジェクトが、 target-type によって指される/参照される型 Target に変換可能かどうかが確認されます:
i) 最も派生したオブジェクトにおいて、 expression が指す/参照するオブジェクトが Target オブジェクトの公開基底クラスの部分オブジェクトであり、かつ expression が指す/参照する部分オブジェクトから派生した Target 型のオブジェクトがただ一つである場合、結果はその Target オブジェクトを指す/参照します。言い換えれば、 dynamic_cast は基底クラスから派生クラスへのポインタ/参照の ダウンキャスト に使用できます。
ii) それ以外の場合、 expression が最も派生したオブジェクトのpublic基底クラスの部分オブジェクトを指す/参照する場合、かつ最も派生したオブジェクトの型が型 Target の明確でpublicな基底クラスを持つ場合、結果は最も派生したオブジェクトの Target 部分オブジェクトを指す/参照する。言い換えれば、 dynamic_cast は同じ基底クラスから派生した2つの型間でポインタ/参照の crosscast (またはside-cast)に使用できる。
iii) それ以外の場合、ランタイムチェックは失敗する。
  • target-type がポインタ型の場合、結果は target-type のヌルポインタ値となる。
  • target-type が参照型の場合、 std::bad_cast 型の ハンドラ にマッチする型の例外がスローされる。

コンストラクタまたはデストラクタ内(直接的または間接的に) dynamic_cast が使用され、 expression が現在構築中/破棄中のオブジェクトを参照する場合、そのオブジェクトは最も派生したオブジェクトと見なされます。 target-type がコンストラクタ/デストラクタ自身のクラスまたはその基底クラスへのポインタまたは参照でない場合、動作は未定義です。

他のキャスト式と同様に、結果は以下の通りです:

  • target-type が参照型の場合、lvalue
  • target-type がポインタ型の場合、rvalue
(C++11まで)
  • target-type がlvalue参照型の場合、lvalue( expression はlvalueでなければならない)
  • target-type がrvalue参照型の場合、xvalue( expression lvalueまたはrvalueの可能性あり (C++17まで) glvalueでなければならない(prvalueは 実体化 される) (C++17以降) 完全なクラス型の)
  • target-type がポインタ型の場合、prvalue
(C++11以降)

注記

ダウンキャストは static_cast でも実行可能ですが、ランタイムチェックのコストを回避できる一方、プログラムが(他のロジックを通じて) expression が指すオブジェクトが確実に Derived であることを保証できる場合にのみ安全です。

一部の形式の dynamic_cast run-time type identification (RTTI)、すなわちコンパイルされたプログラム内の各ポリモーフィッククラスに関する情報に依存しています。コンパイラは通常、この情報の組み込みを無効にするオプションを備えています。

キーワード

dynamic_cast

#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]

関連項目