• static_cast AND dynamic_cast


    类型转换是一种机制,让程序员能够暂时或永久性改变编译器对对象的解释。注意,这并不意味着程序员改变了对象本身,而只是改变了对对象的解释

    在很多情况下,类型转换是合理的需求,可解决重要的兼容问题。因此,程序员经常需要让编译器按其所需的方式解释数据,让应用程序能够成功编译并执行。

    C++编译器仍需向后兼容以确保遗留代码能够通过编译,因此支持下面这样的语法:int* pBuf = (int *)pString ;

    C风格类型转换实际上强迫编译器根据程序员的选择来解释目标对象,强迫编译器遵从自己的意愿。然而,对不希望类型转换破坏其倡导的类型安全的C++程序员来说,这是无法接受的。

    C++提供了一种新的类型转换运算符,专门用于继承的情形,这种情形在C语言中并不存在。

    4个C++类型运算符如下:

    static_cast

    dynamic_cast

    reinterpret_cast

    const_cast

    1、static_cast

    ①用于相关类型的指针之间的转换

    这个相关类型指针是指:具有继承关系的类的指针。

    static_cast实现了基本的编译阶段检查,确保指针被转换为相关类型。使用static_cast可将指针向上转换为基类类型,也可向下转换为派生类类型。

    这改进了C风格类型转换,在C语言中可将指向一个对象的指针转换为完全不相关的类型,而编译器不会报错。(C语言十分自由,而C++对于不同用途的类型转换,会有一些不同的约束)

    注意:static_cast只验证指针类型是否相关(是否有继承关系类的指针),而不执行任何运行阶段检查。(故称之为静态static转换)

    例:

    CBase*pBase = new CBase( ) ;

    CDerived*pDerived = static_cast<CDerived*>(pBase) ;

    由于static_cast只在编译阶段检查转换类型是否相关,而不执行运行阶段检查,因此上面代码能够编译通过,但在运行阶段可能导致意外结果。

    static_cast 与C风格的类型转换类似,只是static_cast只用于有继承相关性的类的指针。它会对这个关系进行检查。

    故:

    用static_cast把指向派生类的基类指针 转换为派生类指针,底层的派生类对象不变,指针的值也不变,只是改变了指针的管辖范围。即:只是改变了编译器的解释方式。(基类指针实际上指向的只是派生类中的基类核心)

    同理,用static_cast把指向派生类的派生类指针 转换为基类指针,也只是改变了编译器对其的解释方式。(static_cast对与多重继承的指针,有特殊处理)

    ②用于内置数据类型的类型转换

    例:

    double dPi = 3.14;

    int nNum =static_cast<int>(dPi) ;

    使用static_cast可让代码阅读者注意到这里使用了类型转换,并指出编译器根据编译阶段可用信息进行了必要的调整,以便执行所需的类型转换。

    2、dynamic_cast

    dynamic_cast动态类型转换在运行阶段执行类型转换。可检查dynamic_cast操作的结果以判断类型转换是否成功。

    dynamic_cast可以把基类指针转换为派生类指针,也可以把派生类指针转换为基类指针。如果转换后可以安全使用,则转换成功,否则其返回NULL。(而static_cast的转换,无法检查转换后的结果是否可以安全使用)

    若基类指针指向的是基类对象,则把它dynamic_cast为派生类指针,则转换会失败。因为这是不安全的转换。

    若基类指针指向的是派生类对象,则把它dynamic_cast为派生类指针,则转换会成功。这是安全的转换。(dynamic_cast比static_cast检查更加严格,但使用范围更小)

    【注意】dynamic_cast必须要在有虚函数的继承里进行。(static_cast则无此限制)

    给定一个基类指针,程序员可能不确定,它目前指向哪种类型,这时可使用dynamic_cast在运行时判断其类型,并在安全时使用转换后的指针。

    dynamic_cast这种在运行阶段识别对象类型的机制成为 运行阶段类型识别RTTI。

    关于RTTI

    RTTI是Runtime Type Information的缩写,从字面上来理解就是执行期的类型信息,其重要作用就是动态判别执行期的类型。

    即:判断基类指针或引用,目前所绑定的类型。

    它有两种方法来识别:

    ①用dynamic_cast类型转换是否成功来识别类型。(dynamic_cast必须要在有虚函数的继承里进行)

    例:

    void fun(CBase* pBase)  
    {  
        CDerived* pDerived = dynamic_cast<CDerived*>(pBase) ;  
        if (pDerived != NULL)  
            pDerived->funDerived ;  
        else  
            pDerived->funBase ;  
    }  

    ②用typeid判断基类地址是否一致来识别类型

    例:

    void fun(CBase* pBase)  
    {  
        CDerived* pDerived = NULL ;  
        if (typeid(*pBase) == typeid(CDerived))  
        {  
        pDerived = static_cast<CDerived*>(pBase) ;  
        pDerived->funDerived ;  
        }  
        else  
            pDerived->funBase ;  
    }  

    编译器从类中虚指针指向的虚函数表的前一表项中提取typeid的值。(请看 C++对象模型简介

    【一般地讲,能用虚函数解决的问题就不要用“dynamic_cast”,能够用“dynamic_cast”解决的问题就不要用“typeid”。】

    RTTI破坏了面向对象的纯洁性。

    首先,它破坏了抽象。用RTTI检测当前基类指针绑定的类型,这与虚函数提倡的隐藏细节,智能实现多态相违背。

    其次,因为运行时类型的不确定性,它把程序变得更脆弱。

    第三,它使程序缺乏扩展性。当你在继承关系中加入了一个新类型时,你可能需要修改涉及RTTI的代码。

  • 相关阅读:
    2018-10-25 模拟测试题解
    bzoj1218 [HNOI2003]激光炸弹题解
    poj1958 Strange Towers of Hanoi 题解
    NOIP2018游记
    6-序列公共用法:索引和切片
    5-编码格式
    4-格式化
    3-课后习题记录-就放这里了
    2-条件语句和循环语句
    1-基本数据类型的操作
  • 原文地址:https://www.cnblogs.com/13224ACMer/p/6284551.html
Copyright © 2020-2023  润新知