隐式类型转换

总结自:隐式类型转换&算数运算符

定义:隐式类型转换是指使用了与表达式规定或当前语境不相符的类型时所进行的类型转换,但是要注意,可能会存在转换出现歧义,从而无法通过编译;一切带有explicit的转换,构造函数,发生的类型转换均不属于隐式转换.

概念总括:

标准转换序列:

一个标准转换顺序可选的为以下:

  • 左值到右值的转换
  • 数值提升或转换
  • 函数指针转换
  • 限定调整

用户定义转换:

非explicit的构造函数和转换函数(与直接初始化不同)

算数转换:

算数转换是指一个表达式,运算符是算数运算符之一,此时有别于隐式类型转换的转换规则.

转换顺序:

  • 标准转换序列
  • 用户定义转换
  • 标准转换序列

接下来将对上述定义部分进行逐一说明:

  • 在语境中的隐式转换:

由于某语句中的表达式需要某种表达式类型,此时就会发生,比如if,逻辑运算符,switch,delete等,要求被转换的表达式的类型遵循转换顺序.
<
值得注意的是:对于此处的用户定义转换,

在C++ 14前,必须拥有一个转换为指定类型(或转换后可继续隐式转换为指定类型)的非explicit的转换函数
在C++ 14及之后则放宽为只要存在有可转换为指定类型(或转换后可继续隐式转换为指定类型)的限定或引用的转换函数即可

>

  • 左值到右值的转换:

这里统一盖称为左值到右值的转换;实际上,只是发生在表达式的运算数类型和当前运算数类型不同时,就会发生该转换.

此处转换实际上细分了三大类,但是总是伴随着泛左值向纯右值的转换以及纯右值之间的转换.


细节上逐一介绍:

  • 泛左值向纯右值的值类型转换

    • 会将任何非函数,数组的泛左值转换为同类型的纯右值,并且若非类类型,则会移除其cv限定,并以原左值的值作为右值的值,并且该转换不会对以下表达式求值:

      • 不求值语境,为nullptr_t的类型(直接转化为nullptr),不进行ODR访问的表达式(此处关于ODR,会有另外的一篇文章做详细描述).
    • 当其为类类型时则视为:
      • 在C++ 17前,以当前左值为参数所进行的一个复制构造函数的调用,构造函数返回的值为一个临时对象,故为一个纯右值表答式
      • 在C++ 17后,改称,该结果对象以泛左值对象复制初始化
      • 并且有,泛左值对象中存在不确定值时,初始化后行为未定义,除非:
      • 该值存在有指向它的指针或存在引用
      • 该值位于静态或TLS
  • 数值提升或转换
  • 数值提升或转换就是将原操作数的数据类型转换为其他的数据类型(可能损失精度),或几乎不会损失精度的类型提升;具体细节如下:

    • 整数类型提升:只需要保证,目标类型的有效值范围是大于等于原类型的即可
    • 整数类型转换:
      • 目标为无符号数发生溢出时,模目标类型的2nn为表示目标类型的位数
      • 目标为有符号数若发生溢出通常是实现定义.
        自C++20起,此时的值将会变成与源值对2n同余的唯一目标类型值.
      • 源为bool时,true为1,false为0
      • 目标是bool时,零值,空指针为false,其余的均为true
      • 浮点数:浮点数在发生类型转换时,如果原值可表示,但是存在多种表示时,由实现定义,或可被精确表示时,值不变,否则未定义,若向整数转换,要求整数对浮点部分截断,无舍入,并且当无法表示时,行为未定义.
      • 指针, NULL可以转换为任何类型的指针类型,void的(要求同cv等级)指针类型可以作为同cv等级的指针转换的目标类型,在基类可访问或无歧义时,可以将派生类的指针转为为其基类的指针(CV等级相同)
        • 函数指针转换:
        • 函数指针实际上很简单,即任何非非静态成员成员函数的id(一个类型为T的函数左值)都可以转换为该函数类型的指针(一个指向改函数类型T的指针纯右值),为什么非静态成员函数不可以呢?因为任何访问非静态成员函数的表达式都是被归为纯右值的,其仅只能作为调用运算符的操作数.
        • 临时变量实质化:
        • 这个是一个纯右值到亡值的过程,即当一个纯右值出现在某些特定表达式时,会发生实质化,变为一个亡值(注,基本上,除了允许纯右值直接作为操作数的表达式之外(例如,所有的隐式类型转换均伴随左值到纯右值的转化为第一步,其后再发生类型转换的,此时类型改变,值类型任然为纯右值,允许作为表达式操作数),均要发生该转换),标准中有如下:

          • 成员访问,下标,这类成员访问的表达式
          • 作为弃值表达式的最终类型
          • 引用绑定到右值时
          • 特殊的:不求值表达式的操作数(sizeof,typeid)
        • 数组到指针的转换:该规则很简答,直接转换为指向数组第一个元素类型的指针即可
        • 限定调整:
        • 对于任何一个带有CV限定的类型T我们都可以做如下对应:
          CV0 P0 CV1 P1 CV2 P2 ... CVn - 1 Pn - 1 CVn U
          例一:如类型const char * * 此时做对应实际上有:
        const char * *
        CV2 U CV1P1 CV0P0

          实际上观察可以发现,从标识符位置起,根据声明查看顺序反向阅读即可得到对应关系,再比如: char * A [];

        char * []
        CV2 U CV1P1 CV0P0

          当然,此处的U可以做任何包含,即可以包含N组(至少留一组)CVn Pn - 1


          由此,上述例1的CV分解实际上U有两层,即U为char或U为const char *


          对于标准转换中的限定调整,其规则实际上很简单,一句话概括就是当且仅当目标的U和对应的CV层数相同且CV限定符一致,或当某级的cv限定符更多时,要求除0级外均有cv限定时才可以转换,例如:

        char ** p;
        const char ** p1 = p; //错误,二级存在更多cv限定,但是1级没有
        const char * const * p2 = p; //正确

        C++ 类型转换(conv.)的更多相关文章

        1. Util应用程序框架公共操作类(三):数据类型转换公共操作类(扩展篇)

          上一篇以TDD方式介绍了数据类型转换公共操作类的开发,并提供了单元测试和实现代码,本文将演示通过扩展方法来增强公共操作类,以便调用时更加简化. 下面以字符串转换为List<Guid>为例进 ...

        2. Util应用程序框架公共操作类(二):数据类型转换公共操作类(源码篇)

          上一篇介绍了数据类型转换的一些情况,可以看出,如果不进行封装,有可能导致比较混乱的代码.本文通过TDD方式把数据类型转换公共操作类开发出来,并提供源码下载. 我们在 应用程序框架实战十一:创建VS解决 ...

        3. 彻底理解c++的隐式类型转换

          隐式类型转换可以说是我们的老朋友了,在代码里我们或多或少都会依赖c++的隐式类型转换. 然而不幸的是隐式类型转换也是c++的一大坑点,稍不注意很容易写出各种奇妙的bug. 因此我想借着本文来梳理一遍c ...

        4. 为C# as 类型转换及Assembly.LoadFrom埋坑!

          背景: 不久前,我发布了一个调试工具:发布:.NET开发人员必备的可视化调试工具(你值的拥有) 效果是这样的: 之后,有小部分用户反映,工具用不了(没反应或有异常)~~~ 然后,建议小部分用户换个电脑 ...

        5. c# 基础 object ,new操作符,类型转换

          参考页面: http://www.yuanjiaocheng.net/webapi/config-webapi.html http://www.yuanjiaocheng.net/webapi/web ...

        6. Struts2日期类型转换

          针对日期类java.util.Date进行类型转换,要求客户端使用"yyyy-MM-dd","yyyy/MM/dd"中的任意一种输入,并以"yyyy- ...

        7. 【.NET深呼吸】基础:自定义类型转换

          照例,老周在开始吹牛之前,先讲讲小故事,这是朋友提出的建议,老TMD写技术有什么了不起的,人人都会写.后来老周想想,也确实,代码谁不会写,能写到有品位有感悟,就不容易做到.于是,老周接受了该朋友的建议 ...

        8. C++四种类型转换方式。

          类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单(TYPE)EXPRESSION,但是c风格的类型转换有不少的缺点,有的时候用c风格的转换是不合适的,因为它可以在任意类型之间转换,比 ...

        9. struts2类型转换

          1. Struts2中的类型转换 我们知道通过HTTP提交到后台的数据,都是字符串的形式,而我们需要的数据类型当然不只字符串类型一种.所以,我们需要类型转换! 在Struts2中,类型转换的概念除了用 ...

        随机推荐

        1. 牛客网Java刷题知识点之什么是单例模式?解决了什么问题?饿汉式单例(开发时常用)、懒汉式单例(面试时常用)、单例设计模式的内存图解

          不多说,直接上干货! 什么是单例设计模式? 解决的问题:可以保证一个类在内存中的对象唯一性,必须对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性. 如何保证? 1.不允许其他程序用new ...

        2. phpstorm 10 注册码

          phpstorm 10 注册码 注册时选择License server,填http://idea.lanyus.com,然后点击OK 网上看评论的结果,亲测,有用!!!

        3. Spring boot-(3) Spring Boot特性1

          本节将深入Spring Boot的细节,可以学到你想使用的或定制的Spring Boot的主要特性. 1. SpringApplication SpringApplication类为引导一个Sprin ...

        4. MVC 模型过滤

          通用返回模型 /// <summary> /// WebApi返回数据的泛型类 /// </summary> /// <typeparam name="T&qu ...

        5. 动态行转列 pivot实现

          declare @sql varchar(8000)    begin              set @sql=''  --初始化变量@sql              select  @sql= ...

        6. intellijidea课程 intellijidea神器使用技巧2-1 无处不在的跳转

          idea快捷键(基于windows平台) 1 书签跳转 Ctrl alt [ ]   ==> 项目之间的跳转 Ctrl shift E ==> 文件之间的跳转(最近编辑的文件) Ctrl ...

        7. hibernate课程 初探一对多映射2-4 Mysql创建数据库表

          1 本节内容: mysql 数据库建表(班级表和学生表) Create table grade(gid varchar(32) primary key, gname varchar(32) not n ...

        8. 使用Ribbon Workbench来修改停用、激活按钮的权限

          在实施的过程中,有时会遇到客户为了管控使用人员的操作或防止使用人员通过停用后再激活来绕开部分逻辑,需要对激活.停用按钮赋予单独的权限.但很遗憾,在Dyanmics CRM中,并没有把停用.激活按钮单独 ...

        9. (C# 基础) 静态字段,静态类,静态方法。

          静态字段被类的所有实例所共享,即此类的所有实例都访问同一内存地址. 所以该内存位置的值变更的话,这种变更对所有的实例都可见. class MyClass { ; ; public void SetVa ...

        10. Android @1x,@2x,@3x 资源文件自动分包工具

          version 1.2 1.修改不用输入扩展名 2.输出路径可选.默认会在输入路径下建文件夹 前沿: 现在开发中ios,android会使用一套图,但是ui设计师给的图命名是以@1x,@2x,@3x这 ...