dynamic_cast 转换

来自cppreference.com
< cpp‎ | language
 
 
 
表达式
概述
值类别(左值 lvalue、右值 rvalue、亡值 xvalue)
求值顺序(序列点)
常量表达式
不求值表达式
初等表达式
lambda 表达式(C++11)
字面量
整数字面量
浮点字面量
布尔字面量
字符字面量,包含转义序列
字符串字面量
空指针字面量(C++11)
用户定义字面量(C++11)
运算符
赋值运算符a=ba+=ba-=ba*=ba/=ba%=ba&=ba|=ba^=ba<<=ba>>=b
自增与自减++a--aa++a--
算术运算符+a-aa+ba-ba*ba/ba%b~aa&ba|ba^ba<<ba>>b
逻辑运算符a||ba&&b!a
比较运算符a==ba!=ba<ba>ba<=ba>=b
成员访问运算符a[b]*a&aa->ba.ba->*ba.*b
其他运算符a(...)a,ba?b:c
运算符的替代表示形式
优先级和结合性
折叠表达式(C++17)
new 表达式
delete 表达式
throw 表达式
alignof
sizeof
sizeof...(C++11)
typeid
noexcept(C++11)
运算符重载
类型转换
隐式转换
const_cast
static_cast
reinterpret_cast
dynamic_cast
显式转换 (T)aT(a)
用户定义转换
 

沿继承层级向上、向下及侧向转换到类的指针和引用。

目录

[编辑] 语法

dynamic_cast < new_type > ( expression )
new_type - 指向完整类类型的指针、到完整类类型的引用,或指向(可选的 cv 限定) void 的指针
expression - new_type 为引用,则为完整类类型的左值表达式,若 new_type 为指针,则为指向完整类类型的指针纯右值。

若转型成功,则 dynamic_cast 返回 new_type 类型的值。若转型失败且 new_type 是指针类型,则它返回该类型的空指针。若转型失败且 new_type 是引用类型,则它抛出匹配类型 std::bad_cast 处理块的异常。

[编辑] 解释

仅下列转换能用 dynamic_cast 进行,除了这种转换会转换走常性易变性的情况。

1)expression 的类型恰是 new_typenew_type 的较少 cv 限定版本,则结果是 expressionnew_type 类型的值。(换言之, dynamic_cast 可用以添加常性。隐式转型和 static_cast 亦能进行此转换。)
2)expression 是空指针值,则结果是 new_type 类型的空指针值。
3)new_type 是到 Base 的指针或引用,且 expression 的类型是到 Derived 的指针或引用,其中 BaseDerived 的单一可访问基类,则结果是到 expression 所标识的对象中 Base 类子对象的指针或引用。(注意:隐式转型和 static_cast 亦能进行此转换。)
4)expression 是到多态类型的引用或指针,且 new_type 是到 void 的指针,则结果是指向 expression 所指向或引用对象的最终导出类的指针。
5)expression 是到多态类型 Base 的指针或引用,且 new_type 是到 Derived 类型的指针或引用,则进行运行时检查:
a) 检验 expression 所指向/标识的最终导出类对象。若在该对象中 expression 指向/指代 Derived 的公开基类,且只有一个 Derived 类型子对象从 expression 所指向/标识的子对象导出,则转型结果指向/指代该 Derived 子对象。(此之谓“向下转型”。)
b) 否则,若 expression 指向最终导出类的公开基类,而同时最终导出类拥有 Derived 类型的无歧义公开基类,则转型结果指向/指代该 Derived (此之谓“侧向转型”。)
c) 否则,运行时检查失败。若 dynamic_cast 用于指针,则返回 new_type 类型空指针值。若它用于引用,则抛出 std::bad_cast 异常。
6) dynamic_cast 用于构造函数或析构函数(直接或间接),且 expression 指代正在构造/析构的对象时,该对象被认为是最终导出对象。若 new_type 不是到构造函数/析构函数自身的类或其基类之一的指针,则行为未定义。

同其他转型表达式,结果是:

  • 左值,若 new_type 是左值引用类型( expression 必须是左值)
  • 亡值,若 new_type 是右值引用类型( expression 为完整类类型,可以是左值或右值 (C++17 前)必须是泛左值 (C++17 起)
  • 否则为纯右值(此情况下,若 new_type 是指针类型)

[编辑] 注意

向下转型亦可用 static_cast 进行,它避免运行时检查的开销,但它仅若程序能保证(通过某些其他逻辑) expression 所指向的对象肯定是 Derived 才安全。

[编辑] 关键词

dynamic_cast

[编辑] 示例

#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* , B 的 V 基类,产生 B*
    dynamic_cast<B*>(a); // 未定义行为: a 有类型 A* , A 非 B 的基类
  }
};
struct D : A, B {
    D() : B((A*)this, this) { }
};
 
struct Base {
    virtual ~Base() {}
};
 
struct Derived: Base {
    virtual void name() {}
};
 
int main()
{
    D d; // 最终导出类
    A& a = d; // 向上转型,可以用 dynamic_cast ,但不必须
    D& new_d = dynamic_cast<D&>(a); // 向下转型
    B& new_b = dynamic_cast<B&>(a); // 侧向转型
 
 
    Base* b1 = new Base;
    if(Derived* d = dynamic_cast<Derived*>(b1))
    {
        std::cout << "downcast from b1 to d successful\n";
        d->name(); // 调用安全
    }
 
    Base* b2 = new Derived;
    if(Derived* d = dynamic_cast<Derived*>(b2))
    {
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // 调用安全
    }
 
    delete b1;
    delete b2;
}

输出:

downcast from b2 to d successful

[编辑] 参阅