名稱空間
變體
操作

dynamic_cast 轉換

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
 
 

沿著繼承層次結構安全地向上、向下和橫向轉換類指標和引用。

目錄

[編輯] 語法

dynamic_cast< 目標型別 >( 表示式 )
目標型別 - 指向完整類型別的指標、指向完整類型別的引用,或指向(可選地 cv 限定的)void 的指標。
表示式 - 如果目標型別是引用,則為完整類型別的左值(C++11 前)glvalue(C++11 起);如果目標型別是指標,則為指向完整類型別的指標的純右值。

[編輯] 解釋

為方便描述,“表示式或結果是T的引用”表示“它是T型別的glvalue”,這遵循decltype的約定(C++11 起)

只有以下轉換可以透過dynamic_cast完成,除非這些轉換會去除 constness(或 volatility)。

1) 如果表示式的型別與目標型別完全相同,或者與目標型別相比具有更少的 cv 限定,則結果是具有目標型別表示式的值。換句話說,dynamic_cast可以用於新增 constness。隱式轉換和static_cast也可以執行此轉換。
2) 如果目標型別是“指向(可能 cv 限定的)Base的指標”,並且表示式的型別是“指向(可能 cv 限定的)Derived的指標”,其中BaseDerived的基類,則結果是
  • 如果表示式是空指標值,則為空指標值;或
  • 否則,指向由表示式指向的Derived物件的唯一Base子物件的指標。換句話說,dynamic_cast可以用於向上轉型指標,從派生類到基類。隱式轉換和static_cast也可以執行此轉換。
3) 如果目標型別是“指向(可能 cv 限定的)Base的引用”,並且表示式的型別是“(可能 cv 限定的)Derived”,其中BaseDerived的基類,則結果是由表示式引用的Derived物件的唯一Base子物件。換句話說,dynamic_cast可以用於向上轉型引用,從派生類到基類。隱式轉換和static_cast也可以執行此轉換。
4) 如果表示式多型型別的空指標值,則結果是目標型別的空指標值。
4) 否則,表示式必須是指向或引用多型型別物件的指標或引用,該物件在其生命週期內或其構造或析構期間,並且其型別與表示式的型別相似(否則行為未定義)
a) 如果表示式是指向(可能 cv 限定的)void 的指標,則結果是指向由表示式指向的最派生物件的指標。
b) 否則,將進行執行時檢查,以檢視由表示式指向/引用的物件是否可以轉換為由目標型別指向或引用的Target型別
i) 如果在由表示式指向/引用的最派生物件中,表示式指向/引用Target物件的公共基類子物件,並且如果只有一個Target型別的物件派生自由表示式指向/引用的子物件,則結果指向/引用該Target物件。換句話說,dynamic_cast可以用於向下轉型指標/引用,從基類到派生類。
ii) 否則,如果表示式指向/引用最派生物件的公共基類子物件,並且最派生物件的型別具有一個明確的公共基類Target型別,則結果指向/引用最派生物件的Target子物件。換句話說,dynamic_cast可以用於交叉轉型(或側向轉型)指標/引用,在從同一個基類派生的兩種型別之間。
iii) 否則,執行時檢查失敗。
  • 如果目標型別是指標型別,則結果是目標型別的空指標值。
  • 如果目標型別是引用型別,則丟擲與std::bad_cast型別的處理程式匹配的型別的異常。

dynamic_cast在建構函式或解構函式中(直接或間接)使用,並且表示式引用當前正在構造/析構的物件時,該物件被認為是最近派生物件。如果目標型別不是建構函式/解構函式自身的類或其基類之一的指標或引用,則行為未定義。

與其他轉換表示式類似,結果是

  • 如果目標型別是引用型別,則為左值
  • 如果目標型別是指標型別,則為右值
(C++11 前)
  • 如果目標型別是左值引用型別(表示式必須是左值),則為左值
  • 如果目標型別是右值引用型別(表示式可以是左值或右值(C++17 前)必須是 glvalue(純右值被物化(C++17 起)的完整類型別),則為 xvalue
  • 如果目標型別是指標型別,則為純右值
(C++11 起)

[編輯] 注意

向下轉型也可以透過static_cast執行,這避免了執行時檢查的開銷,但只有當程式(透過其他邏輯)能夠保證由表示式指向的物件確實是Derived時,才是安全的。

dynamic_cast的某些形式依賴於執行時型別識別(RTTI),即編譯程式中每個多型類的資訊。編譯器通常有選項可以停用包含此資訊。

[編輯] 關鍵詞

dynamic_cast

[編輯] 示例

#include <iostream>
 
struct V
{
    virtual void f() {} // must be polymorphic to use runtime-checked dynamic_cast
};
 
struct A : virtual V {};
 
struct B : virtual V
{
    B(V* v, A* a)
    {
        // casts during construction (see the call in the constructor of D below)
        dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B, results in B*
        dynamic_cast<B*>(a); // undefined behavior: a has type A*, A not a base of 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; // the most derived object
    A& a = d; // upcast, dynamic_cast may be used, but unnecessary
 
    [[maybe_unused]]
    D& new_d = dynamic_cast<D&>(a); // downcast
    [[maybe_unused]]
    B& new_b = dynamic_cast<B&>(a); // sidecast
 
    Base* b1 = new Base;
    if (Derived* d = dynamic_cast<Derived*>(b1); d != nullptr)
    {
        std::cout << "downcast from b1 to d successful\n";
        d->name(); // safe to call
    }
 
    Base* b2 = new Derived;
    if (Derived* d = dynamic_cast<Derived*>(b2); d != nullptr)
    {
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // safe to call
    }
 
    delete b1;
    delete b2;
}

輸出

downcast from b2 to d successful

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
CWG 1269 C++11 對於 xvalue 未執行執行時檢查
表示式如果目標型別是右值引用型別
已執行
CWG 2861 C++98 表示式可能指向/引用型別不可訪問的物件 在這種情況下行為未定義

[編輯] 參考

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

[編輯] 另請參閱