• 【More Effective C++ 条款2】最好使用C++转型操作符


    C的转型方式存在以下两个缺点:

    1)几乎允许你将任何类型转化为任何类型,不能精确的指明转型意图,这样很不安全

    如将一个pointer-to-base-class-object转型为一个pointer-to-derived-class-object(改变一个对象的类型)和将一个pointer-to-const-object转型为一个pointer-to-non-const-object(改变对象的常量性),在旧式C语法中并不区分。

    2)其语法结构难以辨识,容易被混淆

    旧式C转型方式的语法为(type)expression,由一对小括号加上一个对象名称组成,而这种语法结构在C++的任何地方都有可能使用,这就无法很直观地判断出是否是转型操作。

    为了解决C旧式转型的缺点,C++引用了4个新的转型操作符

    1)static_cast

    static_cast基本上拥有和C旧式转型相同的威力与意义

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        //计算两个int型数相除,结果为double型
        int first_num=1;
       int second_num=2;
       double ans1 = (double)first_num/second_num;//旧式C语法
        double ans2 = static_cast<double>(first_num)/second_num;//新式C++转型符
        cout<<ans1<<endl;//0.5
        cout<<ans2<<endl;//0.5
    }

    但是static_cast不能移除表达式的常量性,因为有一个专门的转型操作符const_cast来处理这种情况

    2)const_cast

    const_cast用来移除表达式中的常量性或者变易性,也仅仅只有这个功能

    只能是const_cast<对象的引用或对象的指针>的形式,不能是const_cast<对象>的形式

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
       int num=10;
       const int *cpNum=&num;
       //int *p1=cpNum;          //error:cannot convert from 'const int *' to 'int *'
        int *p2=(int*)cpNum;              //旧式C
        int *p3=const_cast<int*>(cpNum);  //新式C++const_cast移除常量性
    
       cout<<*p2<<endl;//10
        cout<<*p3<<endl;//10
    }

    const_cast最常见的用途就是将某个对象的常量性去除掉

    3)dynamic_cast

    用来执行继承体系中安全的向下转型或跨系转型动作,dynamic_cast支持RTTI运行时类型检查

    比如将指向基类对象的指针或引用转型为子类对象的指针或引用,并且可以得知转型是否成功,如果转型失败会以一个空指针(转型对象为指针)或异常(转型对象为引用)

    需要注意的是,dynamic_cast无法应用在缺乏虚函数的类上,理由如下:

    dynamic_cast的转换是在运行时进行转换,运行时转换就需要知道类对象的信息(继承关系等),而要获得这些信息,就需要通过虚函数表,在C++对象模型中对象实例最前面的就是虚函数指针,通过虚函数表指针可以获取到该类对象的所有虚函数,包括父类的,因为派生类会继承基类的虚函数表,所以通过这个虚函数表,我们就可以知道该类对象的父类,在转换的时候就可以判断对象有无继承关系

    另外,dynamic_cast支持交叉转换,基类A有两个直接派生类B和C,那么将B类对象指针/引用转换为C类对象指针/引用的转换称之为交叉转换

    class Base
    {
        virtual void fun()
        {
            cout << "Base" << endl;
        }
    };
     
    class Derived :Base
    {
        virtual void fun()
        {
            cout << "Derived" << endl;
        }
    };
     
    Base* bbb = new Base();
    Derived* aaa = dynamic_cast<Derived*> (bbb);
    Derived& ccc = dynamic_cast<Derived&> (*bbb);

    如果你需要转换一个不涉及继承体制的请使用:static_cast,dynamic_cast仅仅适用于那种”所指对象至少有一个虚函数“的指针身上。

    4)reinterpret_cast

    最常用的用途是转换“函数指针”,但是函数指针的转型动作,并不具备移植性,某些情况下函数指针转型会导致不正确的结果,所以我们应该尽量避免将函数指针转型

    typedef void (*FuncPtr)()  //FuncPtr是个指针,指向某个函数,后者无需任何自变量,返回值为void

    FuncPtr funcPtrArray[10]   //funcPtrArray是个数组,内含10个FuncPtr

    假设现在有某种原有,需要将一个返回值为int类型的函数放入funcPtrArray

    int dosomething()

    将int类型函数指针放入int类型函数指针数组,如果没有转型的话,是不可能做到这一点的

    funcPtrArray[0]=&dosomething  //错误,类型不符合

    使用reinterpret_cast,可以强迫编译器了解你的意图

    funcPtrArray[0]=reinterpret_cast<FuncPtr>(&dosomething)  //正确,将int类型函数指针转换为void类型


  • 相关阅读:
    SQL执行计划之sql_trace
    Pycharm,出现Invalid VCS root mapping The directory 解决方法
    npm安装cnpm时候报错code EINTEGRITY
    Linux 常用命令汇总
    vue 父子组件传值
    vue 钩子函数的使用
    sql 语句中 order by 的用法
    sql查询的常用语句
    vue 甘特图简单制作
    Node.js安装及环境配置
  • 原文地址:https://www.cnblogs.com/yinbiao/p/11693852.html
Copyright © 2020-2023  润新知