dynamic_cast
转换
来自 cppreference.cn
沿继承层次结构安全地向上、向下和横向转换类指针和引用。
目录 |
[编辑] 语法
dynamic_cast< 目标类型 >( 表达式 ) |
|||||||||
目标类型 | - | 完整类类型的指针,完整类类型的引用,或指向(可选的 cv 限定的)void 的指针 |
表达式 | - | 左值(直到 C++11)泛左值(自 C++11 起),如果 目标类型 是引用;如果 目标类型 是指针,则为指向完整类类型的指针的纯右值 |
[编辑] 解释
为了描述方便,“表达式 或结果是对 T
的引用” 意味着 “它是 T
类型的泛左值”,这遵循 decltype
的约定(自 C++11 起)。
只有以下转换可以使用 dynamic_cast 完成,除非此类转换会移除常量性(或易变性)。
1) 如果 表达式 的类型正好是 目标类型 或 目标类型 的较少 cv 限定版本,则结果是类型为 目标类型 的 表达式 的值。换句话说,dynamic_cast 可用于添加常量性。隐式转换和 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++ 标准。
DR | 应用于 | 已发布行为 | 正确行为 |
---|---|---|---|
CWG 1269 | C++11 | 如果 目标类型 是右值引用类型,则不对将亡值 表达式 执行运行时检查 执行 |
CWG 2861 |
C++98 | 表达式 可能指向/引用类型不可访问的对象 | 在这种情况下,行为未定义 | CWG 2861 |
[编辑] 参考文献
- 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]