理解C++ dynamic_cast

news/2025/3/22 1:52:17

在面向对象程序设计中,有时我们需要在运行时查询一个对象是否能作为某种多态类型使用。与Java的instanceof,以及C#的as、is运算符类似,C++提供了dynamic_cast函数用于动态转型。相比C风格的强制类型转换和C++ reinterpret_cast,dynamic_cast提供了类型安全检查,是一种基于能力查询(Capability Query)的转换,所以在多态类型间进行转换更提倡采用dynamic_cast。本文主要介绍dynamic_cast的意义,用法和注意事项。

 

基本用法

dynamic_cast可以获取目标对象的引用或指针:

T1 obj;

T2* pObj = dynamic_cast<T2*>(&obj);//转换为T2指针,失败返回NULL

T2& refObj = dynamic_cast<T2&>(obj);//转换为T2引用,失败抛出bad_cast异常

 

多态类型

在使用时需要注意:被转换对象obj的类型T1必须是多态类型,即T1必须公有继承自其它类,或者T1拥有虚函数(继承或自定义)。若T1为非多态类型,使用dynamic_cast会报编译错误。下面的例子说明了哪些类属于多态类型,哪些类不是:

//A为非多态类型 

class A{

};

//B为多态类型

class B{ 

    public: virtual ~B(){}

};

//D为多态类型

class D: public A{

};

//E为非多态类型

class E : private A{

};

//F为多态类型

class F : private B{

}

 

横向转型

在多态类型间转换,分为3种类型:

1.子类向基类的向上转型(Up Cast)

2.基类向子类的向下转型(Down Cast)

3.横向转型(Cross Cast)

向上转型是多态的基础,需不要借助任何特殊的方法,只需用将子类的指针或引用赋给基类的指针或引用即可,当然dynamic_cast也支持向上转型,而其总是肯定成功的。而对于向下转型和横向转型来讲,其实对于dynamic_cast并没有任何区别,它们都属于能力查询。为了理解方便,我们不妨把dynamic_cast视为cross cast:

cross-cast

class Shape {

    public: virtual ~Shape();

    virtual void draw() const = 0;

};

class Rollable {

    public: virtual ~Rollable();

    virtual void roll() = 0;

};

class Circle : public Shape, public Rollable {

    void draw() const;

    void roll();

};

class Square : public Shape {

    void draw() const;

};

 

//横向转型失败

Shape *pShape1 = new Square();

Rollable *pRollable1 = dynamic_cast<Rollable*>(pShape2);//pRollable为NULL

//横向转型成功

Shape *pShape2 = new Circle();

Rollable *pRollable2 = dynamic_cast<Rollable*>(pShape2);//pRollable不为NULL

 

指针比较

接上面的例子,在我的机器上pShape2和pRollable2的值(所指向的地址)分别为:

pShape2: 0x0039A294, pRollable2:0x0039A290

说明dynamic_cast在进行转型的时候对不同多态类型设置了不同的偏移量。接下来的问题是

pRollable2 == pShape2

这个表达式应该返回什么呢?答案是:1,即指针比较相等。也许从C语言转到C++的朋友可能会感到困惑,因为在C语言中指针的比较只是值比较而已。显然,对于多态类型,C++编译器为==运算符做了更多的幕后工作来保证指针比较注重对象的同一性而非指针的值。至于实现细节涉及到C++对象模型,这是我还不甚熟悉的内容,故本文不再深入。


https://dhexx.cn/news/show-2510079.html

相关文章

高通芯片命名规则 kryo 485是个什么样的架构?

kryo 485是个什么样的架构&#xff1f; 参考链接&#xff1a; https://www.zhihu.com/question/333289453/answer/741239321 https://blog.csdn.net/weixin_44124323/article/details/110920987 高通芯片命名规则 骁龙后面的三个数字&#xff0c;例如 865&#xff0c;768 代…

《树莓派Python编程入门与实战(第2版)》——2.4 LXDE图形界面

本节书摘来自异步社区《树莓派Python编程入门与实战&#xff08;第2版&#xff09;》一书中的第2章&#xff0c;第2.4节&#xff0c;作者[美] Richard Blum Christine Bresnahan&#xff0c;陈晓明 马立新 译&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看。…

Linux下切换Python版本的几种方法

Linux下切换Python版本的几种方法 参考链接&#xff1a; 1、https://www.cnblogs.com/feynxd/p/11367806.html 2、https://blog.csdn.net/weixin_34355559/article/details/93215997 本篇博文面向Linux用户&#xff0c;在Ubuntu下测试通过 0 为什么需要有两个版本的Python…

软件开发、硬件开发、IPD产品开发 及 工程开发各阶段划分

软件开发、硬件开发、IPD产品开发 及 工程开发各阶段划分 参考链接:https://zhuanlan.zhihu.com/p/427246890 1、软件开发阶段划分: Alpha、Beta、RC、GA/MR1 2、华为硬件开发阶段划分: V1、V2 、V3 、V4 、VN1、VN2 其他硬件开发阶段划分1: ES、 CS、 PP、M…

《Android 平板电脑开发实战详解和典型案例》——2.6节可展开列表—— ExpandableListView...

本节书摘来自异步社区《Android 平板电脑开发实战详解和典型案例》一书中的第2章&#xff0c;第2.6节可展开列表—— ExpandableListView&#xff0c;作者 吴亚峰 , 杜化美 , 索依娜&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看 2.6 可展开列表—— Expand…

嵌套类与局部类

一、嵌套类 在一个类的内部定义另一个类&#xff0c;我们称之为嵌套类&#xff08;nested class&#xff09;&#xff0c;或者嵌套类型。之所以引入这样一个嵌套类&#xff0c;往往是因为外围类需要使用嵌套类对象作为底层实现&#xff0c;并且该嵌套类只用于外围类的实现&…

DBA避坑宝典:Oracle运维中的那些事儿

对于Oracle运维中的那些事儿&#xff0c;我的最终目的&#xff1a;不是比谁更惨&#xff0c;而是能够从中吸取经验和教训。 从我的理解来看&#xff0c;我会从下面的几个方面来进行说明DBA运维中的一些事儿。 每个部分都是非常关键的&#xff0c;缺一不可&#xff0c;而且每一部…

再论空指针检测问题

某些C/C编程的书中,曾经提到如何判断指针是否为空的问题.很显然,if (p NULL), if (p 0) 和if(p),都能够完成这一任务,差别在于可读性方面.我们分别加以讨论. 1. if (p NULL) 相当多的文章建议采用,他们中的部分人甚至认为,其他做法都是错误的.这个形式一个变种是 if (NULL …

车联网V2X介绍之:通信芯片

车联网V2X介绍之&#xff1a;通信芯片 参考链接&#xff1a;https://zhuanlan.zhihu.com/p/115276002 目前&#xff0c;我国产业化进程逐步加快&#xff0c;产业链上下游企业已经围绕LTE-V2X形成包括通信芯片、通信模组、终端设备、整车制造、运营服务、测试认证、高精度定位及…

《SQL入门经典(第5版)》一一1.6 问与答

本节书摘来自异步社区出版社《SQL入门经典&#xff08;第5版&#xff09;》一书中的第1章&#xff0c;第1.6节&#xff0c;作者&#xff1a;【美】Ryan Stephens , Ron Plew , Arie D.Jones&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看。 1.6 问与答 SQL入…