• 类型转换


    类型转换

    如果两种类型可以相互转换,那么它们就是关联的。

    隐式类型转换

    • 在大多数表达式中,比 int 类型小的整型值首先会被提升为较大的整数类型。
    • 在条件中,非布尔值转换成布尔值。
    • 在初始化过程中,初始值转换成变量的类型。
    • 在赋值语句中,右侧对象转换成左侧对象的类型。
    • 如果算术运算或关系运算的对象有多种类型,需要转换成同一种类型。

    算术转换

    算术转换的含义是把一种算术类型转换成另外一种算术类型。

    整型提升

    整型提升是把小整数类型转换成较大的整数类型。

    • 对于 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 中最小的类型。

    无符号类型的运算对象

    如果一个运算对象是无符号类型,另外一个运算对象是带符号类型的:

    • 无符号类型不小于带符号类型,那么带符号运算对象转换成无符号的。例如:两个类型分别是 unsigned intint,则 int 类型的运算对象转换成 unsigned int
    • 带符号类型大于无符号类型,此时转换的结果依赖于机器:如果无符号类型的所有值都能存在该带符号类型中,则无符号类型的运算对象转换成带符号类型;如果不能,那么带符号类型的运算对象转换成无符号类型。例如:如果两个运算对象的类型分别是 longunsigned int,并且 intlong 的大小相同,则 long 类型转换成 unsigned int;如果long 类型占用的空间比 int更大, 则 unsigned int 类型转换成 long 类型。
    boo flag;   
    char cval;
    short sval;
    unsigned short usval;
    int ival;
    unsigned int uival;
    long lval;
    unsigned long ulval;
    float fval;
    double dval;
    
    3.1415: + 'a';    //'a'被提升为int,然后该int再转换成long double
    dval + ival;      //ival转换成double
    dval + fval;     //fval转换成double
    flag = dval;     //dval是0,则flag是false,否则flag是true
    cval + fval;    //cval提升为int,然后该int被提升为float
    sval + cval;    //savl、cval都被提升为int
    cval + lval;    //cval 转换成long
    ival + ulval;   //ival转换成unsigned long
    usval + ival;   //根据unsigned short和int所占空间大小进行提升
    uival + lval;   //根据unsigned int和long所占空间大小进行转换
    

    其他隐式类型转换

    数组转换成指针:在大多数用到数组的表达式中,数组会自动转换成指向数组首元素的指针。
    指针的转换:

    • 常量整数值0或者字面值 nullptr 能够转换成任意的指针类型。
    • 指向任意非常量的指针都能转换成 void*
    • 指向任意对象的指针都能转换成 const void *

    转换成布尔类型:存在一种从算术类型或指针类型自动向布尔类型自动转换的机制。如果指针或算术类型的值为0,转换的结果是 false,否则转换结果是 true
    转换成常量:允许将指向非常量类型的类型转换成指向相应的常量类型的指针,对于引用也是这样。也就是说,如果T是一种类型,我们就能将指向T的指针或引用转换成指向 const T 的指针或引用。

    int i;
    const int &j = i;       //非常量转换成const int 的引用
    const int *p = &i;      //非常量的地址转换成const的地址
    int &r = j,*q = p;      //错误,不允许const转换成非常量
    

    类类型定义的转换:类类型能定义由编译器自动执行的转换,不过编译器每次只能执行一种类类型的转换。
    例如:

    • 使用标准库 string 类型的地方使用C风格字符串。
    • while(cin>>s)while把条件部分 cin 转换成布尔值。

    显示转换

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

    命名的强制类型转换

    命名的强制类型转换形式为:

    cast_name<type> (expression);
    

    其中,type 是转换的目标类型而 expression 是要转换的值,如果 type 是引用类型,则结果是左值。
    cast_namestatic_cast、dynamic_cast、const_cast、reinterpret_cast 中的一种。

    static_cast

    任何具有明确定义的类型转换,只要不包含底层 const,都可以使用 static_cast
    例如:

    double slope = static_cast<double>(j) / i;      //浮点数除法 
    

    当需要把一个较大的算术类型转换成较小的类型,static_cast 非常有用,此时强制类型转换会提醒编译器忽略潜在的精度损失,否则编译器会报警告信息。

    const_cast

    const_cast 只能改变运算对象的底层 const

    const char *pc;
    char *p = const_cast<char*>(pc);    //正确,但是通过p写值是未定义的行为
    

    一旦去掉某个对象的const性质,编译器就不再阻止对该对象的写操作,如果对象本身不是一个常量,使用强制类型转换获得写权限是合法的行为。然而如果对象是一个常量,再使用 const_cast执行写操作就会产生未定义的结果。

    reinterpret_cast

    reinterpret_cast 通常为运算对象的位模式提供较低层次的重新解释。

    int *ip;
    char *pc = reinterpret_cast<char*>(ip);
    

    使用 reinterpret_cast 是十分危险的,在这里必须始终牢记, pc 所指向的真实对象是 int 而不是 char,如果把 pc 当成普通的字符指针使用就可能发生运行时错误,例如:

    string str(pc);
    

    reinterpret_cast 本质上依赖于机器,向安全的使用 reinterpret_cast 必须对涉及的类型和编译器实现转换的过程十分了解。

    旧式的强制类型转换

    早期版本的C++中,显示的强制类型转换有两种形式:

    type (expr);    //函数形式的强制类型转换
    (type) expr;    //C语言风格的强制类型转换
    
  • 相关阅读:
    手写spring事务框架, 揭秘AOP实现原理。
    centos7修改端口登陆
    数据库的锁机制
    linux安装mysql5.6
    SpringMVC数据格式化
    Java处理小数点后几位
    docker学习(七)常见仓库介绍
    docker学习(六) Docker命令查询
    docker学习(六)
    docker学习(五)
  • 原文地址:https://www.cnblogs.com/xiaojianliu/p/12498325.html
Copyright © 2020-2023  润新知