C++中的类型转换总结

1、 类型转换
    1、在下面这些表达式中,编译器会自动转换运算对象的类型:
        (1) 在大多数表达式中,比int类型小的整型值首先提升为较大的整数类型。
        (2) 在条件中,非布尔值转换成布尔类型。
        (3) 初始化过程中,初始值转换成变量的类型;在赋值语句中,右侧运算对象转换成左侧运算对象的类型。
        (4) 如果算术运算或关系运算的运算对象有多种类型,需要转换成同一种类型。
1.1、算术转换    
    1.1.1、运算符的运算对象将转换成最宽的类型。
    1.1.2、当表达式中既有浮点类型也有整形类型时,整数值将转换成相应的浮点类型。
    1.1.3、整型提升负责把小整数类型转换成较大的整数类型。对于bool、char、signed char、unsigned char、short和unsigned short等类型来说,只要它们所可能都能存在于int里,它们就会提升成int类型。否则提升成unsigned int类型。较大的char类型(wchar_t、char16_t、char32_t)提升成int、unsigned int、long、unsigned long、long long 和unsigned long long中最小的一种类型。前提是转换后的类型要能容纳原类型所有可能的值。
    1.1.4、对于无符号类型和有符号类型运算
        (1) 如果无符号类型不小于带符号类型,那么带符号的运算对象转化成无符号的
        (2) 如果带符号类型大于无符号类型,那么若无符号类型的所有值都能存在该带符号类型中,则无符号类型的运算对象转换成带符号类 型。若不能,则带符号类型的运算对象转换成无符号类型。
    1.1.5、例子
        3.14159L + 'a';   //'a'提升成int,然后该int值转换成long double
        double dval;
        int ival = dval;   //dval转换成(切除小数部分后)int
        bool flag = dval;  //如果dval为0,则flag为false;如果dval为1,则flag为1
        char cval;
        float fval;
        cval + fval;   //cval提升成int,然后该int值转换成float
        short sval;
        cval + sval;  //cval和sval都提升成int,sizeof(cval+sval)结果是4
        long lval;
        cval + lval;  //cval直接转成long,不用先转成int,因为都是整型,而且long比int大
        unsigned long ulval;
        ival + ulval;  //ival转成unsigned long
        unsigned short usval;
        usval + ival;  //根据unsigned short 和 int所占空间的大小进行提升
        unsigned int  uival;
        uival + lval; //根据unsigned int 和 long所占空间的大小进行提升
1.2、 其他隐式类型转换
    1.2.1、数组转化成指针:在大多数用到数组的表达式中,数组自动转换成指向数组首元素的指针。
        (1) 当数组被用作decltype关键字的参数或者作为取地址符、sizeof及typeid等运算符的运算对象时,数组不会转换成指向数组首元素的指针,此时数组名表示的时是整个数组比如sizeof(数组名)得到的是整个数组的大小。如果使用一个引用来初始化数组,数组也不会转换成指向数组首元素的指针。
    1.2.2、指针的转换:常量整数值0或者字面值nullptr能转换成任意指针类型;指向任意非常量的指针能转换成void *,反之不行;指向任意对象的指针能转换成const void *;
    1.2.3、转化成布尔类型:存在一种从算术类型或指针类型向布尔类型自动转换的机制。如果指针或算术类型的值为0,转换结    果是false;否则转换结果是true。
    1.2.4、允许将指向非常量类型的指针转换成指向相应的常量类型的指针。相反的转换则不存在。
     1.2.5、类类型定义的转换:类类型能定义由编译器自动执行的转换,不过编译器每次只能执行一种类类型的转换。
1.3、 显示转换
强制类型转换形式如下:
cast-name<type>(expression);
    1.3.1、static_cast:任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast。
        (1) 当需要把一个较大的算术类型赋值给较小的类型时,static_cast非常有用。此时,强制类型转换告诉程序的读者和编译器:我们知道并且不在乎潜在的精度损失。一般来说,如果编译器发现一个较大的算术类型试图赋值给较小的类型,就会给出警告信息;但是当我们执行了显示的类型转换之后,警告信息就会关闭。
        (2) static_cast对于编译器无法自动执行的类型转换也非常有用。如下
            void* p = &d;
            double* dp = static_cast<double*>(p);  //虽然void*不能自动转换为type*,但可以通过显示的强制类型转换完成
            注意虽然能使用static_cast能将void*转换成其他类型,但是不能使用static_cast进行除此之外指针类型之间的转换。如下
                int *inp;
                char *chp = static_cast<int*>(inp);//错误
   1.3. 2、const_cast:
        (1) 只能改变运算对象的底层const。
        (2) 只有const_cast能改变表达式的常量属性。使用其他形式的命名强制类型转换改变表达式的常量属性都将引发编译器错误。如下:
            const char *cp;
            char *q = static_cast<char*>(cp); //错误:static_cast不能转换掉const性质
            static_cast<string>(cp); //正确:字符串字面值转换成string类型
            const_cast<string>(cp);//错误:const_cast只能改变常量属性
    1.3. 3、reinterpret_cast:通常为运算对象的位模式提供较低层次上的重新解释。如下
        int *ip;
        char *pc = reinterpret_cast<char*>(ip);
        注意pc指向的真实对象是一个int而非字符。如果把pc当成普通的字符指针使用可能在运行时发生错误。如
        string str(pc);
        因为我们使用了reinterpret_cast将int的地址初始化pc,所以编译器在转换之后会认为pc是char*类型的(编译器无法知道pc实际存放的是指向int的指针)。因此使用pc初始化str可能会导致错误。
    1.3. 4、dynamic_cast:支持动态类型转换
        1、使用形式如下:
            dynamic_cast<type*>(e);//e必须是一个有效的指针
            dynamic_cast<type&>(e);//e必须是一个左值
            dynamic_cast<type&&>(e);//e不能是左值
            对于以上三种形式,type必须是一个类类型,并且通常情况下应该含有虚函数。而且e的类型必须满足以下三个条件中的任意一个。
                (1) e的类型是目标类型type的公有派生类
                (2) e的类型是目标类型type的公有基类
                (3) e的类型就是目标类型type的类型
            如果一条dynamic_cast语句执行得转化目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个bad_cast异常。
        2、例如:假定Base类至少含有一个虚函数,Dervied是Base的公有派生类,指针bp指向Base。
            if(Derived *dp = dynamic_cast<Derived*>(bp))
            {
                //使用dp指向的Derived对象
            }
            else
            {
                //使用bp指向的Base对象
            }
            将Baed*类型的指针bp转换成Derived*,如果转换成功dp就指向Derived对象,执行的就是if语句内部使用Derived操作的代码。如果 失败,就执行else语句块中相应的Base操作。这样做的好处是同时完成类型转换和条件检查。并且dp在if语句外部是不可访问的,这 样即使转换失败,后续的代码即使没有作相应的判断也不会接触到这个未绑定的指针。
        3、例如:和2一样
            void func(const Base &b)
            {
                try{
                    const Derived &d = dynamic_cast<const Derived&>(b);
                    //使用b引用的Derived对象
                }catch(bad_cast){
                    //处理类型转换失败的情况
            }
            对引用的dynamic_cast和指针的不同在于当引用类型转换失败时,程序抛出一个名为std::bad_cast的异常,该异常定义在typeinfo 标准库头文件中。

1.3.5 虽然有时候不得不使用强制类型转换,但这种方法本质上是十分危险的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值