73.dynamic_cast in C++
🍅概述
当我们想要做特定类型的类型转换时,有C的方式,也有C++的方式
C的方式就是类似于
(int)a
这般转换而C++的方式就是使用比如
static_cast, const_cast
的转换,dynamic_cast
亦是如此
dynamic_cast
是作为一种安全机制提供给我们的转换类型方式,它做了额外的工作来确保我们实际的类型转换是有效的类型转换
dynamic_cast
更像一个函数,认识到这点很重要。它不想编译时进行的类型转换,而是是在运行时计算,所以会有一定运行成本
🍅何时用
dynamic_cast
是专门用于沿继承层次结构进行的强制类型转换,即dynamic_cast
只用于多态类类型。意思dynamic_cast
大多是用于子类父类之间的类型转换(比如从基类型转换为派生类型,或者将子类转换为基类)
比如有实体类,它的子类是敌人类和玩家类。如果把一个实体对象(这个实体对象既可以是实体类,也可以是敌人类和玩家类)转换为一个玩家对象,这会造成不确定因素。如果是玩家转换为玩家实体,那还算好。如果是敌人转换为玩家实体,敌人实体就会访问玩家独有的数据或者修改玩家独有的函数,则就会造成程序崩溃。因此,dynamic_cast
常被用来做验证(如果将敌人实体转换为玩家实体,则会转换失败,dynamic_cast
会返回一个NULL
指针,也就是0)
#include <iostream>
#include <string>
class Entity {
public:
virtual void PrintName() {} //这里添加虚函数是为了标志着它是多态类型,只有多态类型才能使用dynamic_cast
};
class Player : public Entity {
};
class Enemy : public Entity {
};
int main() {
Player *player = new Player();
Entity *actuallyPlayer = player; //隐式转换,因为player是Entity的子类,所以player上的和Entity相同的部分可以转换到Entity上(当然要丢掉player拓展的部分)
//上述是将子类转换为基类
//下面是基类转换成子类,就会涉及到转换的问题
Entity *actuallyEnemy = new Enemy(); //指向实体的指针指向了一个敌人类!!!
Player *player1 = dynamic_cast<Player*>(actuallyEnemy); //这样就会失败,将敌人转换为玩家
Player *player2 = dynamic_cast<Player*>(actuallyPlayer); //这样会成功
}
那么dynamic_cast
是如何知道实体实际上是玩家而不是敌人的呢?要做到这一点是因为它储存了运行时的类型信息(所谓的RTTI),所以它的工作是需要RTTI是打开状态才行(VS可以把RTTI给关了)
而因为dynamic_cast
是可以鉴别是否转换成功的所以可以有如下操作
#include <iostream>
#include <string>
class Entity {
public:
virtual void PrintName() {} //这里添加虚函数是为了标志着它是多态类型,只有多态类型才能使用dynamic_cast
};
class Player : public Entity {
};
class Enemy : public Entity {
};
int main() {
Entity *actuallyEnemy = new Enemy();
if (dynamic_cast<Player*>(actuallyEnemy)) {
//如果转换成功,则往下执行下一步操作
}
//如果无,则无视上面的语句接着往下走
}