各位,不到一个月的时间我再次出现。继上一次的坑,我们继续讲解C++11中的强制转化类型。上一次说了static_cast和reinterpret_cast两种转化方式,这两种基本涵盖所有的C语言强制类型转化,但其实还是差了点火候,今天我们继续讲解剩余的两种方式,废话不多说,马上发车。
第三种:dynamic_cast<类型>(转换对象)动态类型转化(基类下行转化),这种转化方式是完全是为了适应C++的面向对象编程,C++11强制转化最有意义的转化方式就是dynamic_cast。
我们都知道,C++面向对象编程中,最核心的部分就是基类和派生类之间的爱恨情仇,比如最基本的继承,还有多继承,虚继承,多态等特性,其中最重要也使用最广泛的也是多态,了解过架构的朋友都知道23种设计模式中的常用设计模式(除了单例),大部分都需要使用多态来完成,最根本的原因是因为派生类可以转化为父类进行使用,再由父类转化为需要的派生类,这样就能大大降低代码的耦合度,提高内聚性。
但其实多态是有一定缺陷的,dynamic_cast就很好的解决了这个问题,这个等一下再拿实际案例说,现在先讲一下dynamic_cast的使用条件:
1.作用对象必须是指针或者引用类型(引用其实也是指针)。
2.上行不安全,下行安全(简单来说就是父类到子类的转化安全,子类到父类不安全)
OK,那么使用条件都清楚了之后,我们来讲一下多态的缺陷以及dynamic_cast是如何解决的。接下来我假设一个场景:你是一位程序员,现在需要你开发一款动物世界的游戏,游戏中有很多动物做着固定和非固定的动作,每个动物有着自己的特点,与现实世界相符。那么现在需要你设计一个功能,将别的程序员传入的动物类,转化为指定的动物完成相应的动作。老司机的你很快就想到了怎么做,定义动物类包含动物的基本属性,将动物相应动作写成纯虚函数,然后派生各个子类,重写动作函数。最后利用多态特点(替父从军),完成参数的传递,达到低耦合,高内聚的特点。如下图所示:
你完成了前期的工作需求,可是当action函数内部不止Dog有动作的时候呢?当有Cat的时候怎么做呢?如果同时需要在内部做出动作呢?如果使用传统的多态是不是很麻烦,甚至就脱离了多态本来的性质,那么dynamic_cast就该出场了,接下来看我表演,如下图所示:
怎么样?是不是很神奇,只要使用了我们的动态转化进行内部处理,就可以轻易解决这个问题,会让多态的应用场景变得更加的方便。dynamic_cast转化方式在下行转化的时候会自动检查转化是否合理,如果不合理的话,那么就会返回一个NULL的地址,告诉使用者转化失败,这个就是C++转化方式改进最大的地方,就是为了适应多态的使用场景,不再复杂化。
除此之外,dynamic_cast对引用的转化也具有兼容性,当引用类型被下行强转时,如果转化失败会抛出异常std::bad_cast类型对象,当有异常抛出,程序再进行捕捉后,那么程序就不会访问非法地址和宕机,看我以下代码:
我们可以清晰的看到,当转化失败的时候程序抛出了异常,而我们也顺利捕捉到异常(点赞过五十更新异常捕捉),因为引用内部实现就是用的指针,所以原则上来说dynamic_cast只能对指针使用,以上就是dynamic_cast的核心用法,接下来我们将最后一种。
第四种:const_cast<类型>(转化对象)去常量转化(去掉const属性),这种转化方式其实很好理解,这个名字就已经暴露了,它唯一的作用就是去const属性,废话不多说,直接上代码:
这是它唯一的用法,但是需要注意的是,去常量的对象指向的内存是否可以被修改,这个问题是必须注意的,如下所示是不允许的:
这个涉及到内存储存的问题,暂时不解释,等到哪天更新这块再说。好了,以上就是最后的两种转化方式,其中最重要的就是dynamic_cast的转化,注意:dynamic_cast转化方式下行是安全的,但是上行转化是不安全的,切记。
最后,老C++程序员给你们的建议就是能不用强制类型转化就不用,如果一定要使用,尽量使用C++方式转化,其次一定要明白转化后和转化前的前后关系。
好了,这篇文章到此结束,主要是快下班了,哈哈。我们下次再见,点赞越多发车越快。