dynamic_cast
转换
来自 cppreference.cn
沿着继承层次结构安全地向上、向下和横向转换类指针和引用。
目录 |
[编辑] 语法
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]