dynamic_cast
conversion
安全地在继承层次结构中向上、向下及横向转换类和引用的指针。
目录 |
语法
dynamic_cast<
目标类型
>(
表达式
)
|
|||||||||
| 目标类型 | - | 指向完整类类型的指针、完整类类型的引用,或指向(可选地带有 cv 限定符) void 的指针 |
| 表达式 | - | 左值 (C++11 前) 泛左值 (C++11 起) (当 目标类型 为引用时需为完整类类型);纯右值(当 目标类型 为指针时需为指向完整类类型的指针) |
说明
为便于描述,“
表达式
或结果为
T
的引用”意指“它是
T
类型的泛左值”
,这遵循了
decltype
的约定
(C++11 起)
。
只有以下转换可以通过 dynamic_cast 实现,除非这些转换会 去除常量性 (或易变性)。
Base
的指针”,且
expression
的类型为“指向(可能带 cv 限定符)
Derived
的指针”,且
Base
是
Derived
的基类,则结果为:
- 若 expression 为空指针值,则结果为空指针值;否则
-
结果为指向由
expression
所指
Derived对象中唯一Base子对象 的指针。换言之, dynamic_cast 可用于对指针进行 向上转型 (从派生类到基类)。隐式转换和 static_cast 同样可以执行此转换。
Base
的引用”,且
expression
的类型为“(可能带有 cv 限定符的)
Derived
”,其中
Base
是
Derived
的基类,则结果为
expression
所引用的
Derived
对象中唯一的
Base
子对象。换言之,
dynamic_cast
可用于对引用进行
向上转型
(从派生类到基类)。隐式转换和
static_cast
同样可以执行此转换。
Target
类型:
Target
对象的公开基类子对象,且仅存在一个
Target
类型对象派生自
expression
指向/引用的子对象,则结果指向/引用该
Target
对象。换言之,
dynamic_cast
可用于将指针/引用从基类向派生类进行
向下转型
。
Target
类型基类,则结果指向/引用最终派生对象的
Target
子对象。换言之,
dynamic_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 依赖于 运行时类型识别 (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 << "downcast from b1 to d successful\n"; d->name(); // 可安全调用 } Base* b2 = new Derived; if (Derived* d = dynamic_cast<Derived*>(b2); d != nullptr) { std::cout << "downcast from b2 to d successful\n"; d->name(); // 可安全调用 } 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]