命名空间
变体
操作

dynamic_cast 转换

来自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句(循环)
for
范围 for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (在 C++17* 中弃用)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 

沿继承层次结构安全地向上、向下和横向转换类指针和引用。

目录

[编辑] 语法

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 的指针”,使得 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)必须是完整类类型的泛左值(纯右值被物化(自 C++17 起)),则为将亡值
  • 如果 目标类型 是指针类型,则为纯右值
(自 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++ 标准。

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]

[编辑] 参见