dynamic_cast
轉換
來自 cppreference.com
沿著繼承層次結構安全地向上、向下和橫向轉換類指標和引用。
目錄 |
[編輯] 語法
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
的指標”,其中Base
是Derived
的基類,則結果是- 如果表示式是空指標值,則為空指標值;或
- 否則,指向由表示式指向的
Derived
物件的唯一Base
子物件的指標。換句話說,dynamic_cast可以用於向上轉型指標,從派生類到基類。隱式轉換和static_cast也可以執行此轉換。
3) 如果目標型別是“指向(可能 cv 限定的)
Base
的引用”,並且表示式的型別是“(可能 cv 限定的)Derived
”,其中Base
是Derived
的基類,則結果是由表示式引用的Derived
物件的唯一Base
子物件。換句話說,dynamic_cast可以用於向上轉型引用,從派生類到基類。隱式轉換和static_cast也可以執行此轉換。b) 否則,將進行執行時檢查,以檢視由表示式指向/引用的物件是否可以轉換為由目標型別指向或引用的
Target
型別i) 如果在由表示式指向/引用的最派生物件中,表示式指向/引用
Target
物件的公共基類子物件,並且如果只有一個Target
型別的物件派生自由表示式指向/引用的子物件,則結果指向/引用該Target
物件。換句話說,dynamic_cast可以用於向下轉型指標/引用,從基類到派生類。ii) 否則,如果表示式指向/引用最派生物件的公共基類子物件,並且最派生物件的型別具有一個明確的公共基類
Target
型別,則結果指向/引用最派生物件的Target
子物件。換句話說,dynamic_cast可以用於交叉轉型(或側向轉型)指標/引用,在從同一個基類派生的兩種型別之間。iii) 否則,執行時檢查失敗。
- 如果目標型別是指標型別,則結果是目標型別的空指標值。
- 如果目標型別是引用型別,則丟擲與
std::bad_cast
型別的處理程式匹配的型別的異常。
當dynamic_cast在建構函式或解構函式中(直接或間接)使用,並且表示式引用當前正在構造/析構的物件時,該物件被認為是最近派生物件。如果目標型別不是建構函式/解構函式自身的類或其基類之一的指標或引用,則行為未定義。
與其他轉換表示式類似,結果是
|
(C++11 前) |
|
(C++11 起) |
[編輯] 注意
向下轉型也可以透過static_cast執行,這避免了執行時檢查的開銷,但只有當程式(透過其他邏輯)能夠保證由表示式指向的物件確實是Derived
時,才是安全的。
dynamic_cast的某些形式依賴於執行時型別識別(RTTI),即編譯程式中每個多型類的資訊。編譯器通常有選項可以停用包含此資訊。
[編輯] 關鍵詞
[編輯] 示例
執行此程式碼
#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]