不存在从void转换到sqlist的适当构造函数_第五文:隐式转换和临时对象

声明:老样子,侵权或者理解不到位的地方,请后台通知我们。本公众号致力于从最基础的知识点入手,尽力搞清楚每一个知识点背后的真相,让大伙告别“两行代码,三个bug, 五个warning”的尴尬局面。

今天主要解决两个问题:

  1. 什么是隐式转换

  2. 什么是临时对象

1. 隐式转换

    我们简单点说就是编译器“偷偷的”帮你把一个数据类型转换成另外一个数据类型的转换:

      1.内置类型:

        比如说:int A =1; float B = 1.1;float C =A+B;

以上例子中就有一个隐式转换,编译器把A先转换成一个float类型的临时对象,然后在用这个临时对象与B相加赋值给C。当不同类型的内置类型数据做运算的时候,隐式转换规则如下:

9c15d59b86524e49c3f8d8c020717548.png

以上转换如果做静态代码检测应该是会报出warning的,所以我们在做计算的时候可以告诉显示的告诉编译器,这种转换是可以接受的,这个时候可以显示的进行转换,如上面可以写成: float C =(float)A+B。

注意:对于内置类型的转换(显示或者隐式)要注意以下两个方面:

  1. 显示将整型从高字节转成低字节,注意上限丢失。

  2. float类型与整型之间的转换,如果有浮点保护,注意转换是否满足个芯片对于浮点保护的规则。

       2.类对象隐式转换

       大家都见过,在只有一个形参的构造函数前面(对于那些有N个参数,但是又N-1个已经又默认值的构造函数也属于这一类),我们经常会加一个explicit关键字。如(下面是不加explicit的情况):

class test:

{

    test(int A){}  //一个参数

    test(&test, int A = 0){} //两个参数,但是有一个已经默认了

}

当没有explicit的时候,我们看下以下代码:

test B = 1;我的天,这个时候你可能要吐槽了,会不会写代码,一个int类型怎么能用来初始化一个类对象? 但实际编译的时候就是没报错

于是我们加上explicit:

class test:

{

   explicit test(int A){}  //一个参数

   explicit test(&test, int A = 0){} //两个参数,但是有一个已经默认了

}

test B = 1再来个一样的代码,怎么回事,这次编译器报错了!

这就是另外一个我们不常关注的隐式转换的点:

对于只有一个参数的构造函数,编译器会将对应参数类型的数据"偷偷的"转换成类对象。也就是说在没有用到explicit的时候,对于test A = 2,编译器做了以下事情:

  1. 调用与参数类型相同的构造函数,产生一个临时对象.  test temp(2).

  2. 然后调用拷贝构造函数将temp赋值给A。

当用到explicit之后:

     我们必须显示的去调用构造函数,否则编译器就会报错。

有了这个explicit之后我们对拷贝构造函数的“操作权”就牢牢掌握在自己手里了,一旦发现有“隐式转换”的“不规范”代码,编译器就会报错。

2. 临时对象

    老样子,用最直白的表达来解释看似很难懂的专业词汇,临时对象简单点理解就是代码开发者无形中给了编译器一个暗示,让他“偷偷的”给你创造一个临时对象。

无形中意味着如果没有关注过,开发者永远都不知道自己做了什么,让编译器产生了这种要产生对象的错觉。

就好比我们上面的例子:test A =2, 你永远也不知道实际已经有个temp对象被生成了。

那么什么时候会产生临时对象呢?笔者总结了以下几点:

  1. 以值传递的形参,传进函数的形参实际上是在栈上的实参的一个拷贝。对形参做任何改变都不会影响实参的值。

  2. 像我们上一节说的隐式类型转换

  3. return一个类对象的时候会在栈上构造一个临时对象。

  4. 非堆上定义的一个无名对象, 如test &Aref=test(3)这个引用实际上绑定的是个临时对象。

因为临时对象的产生既影响软件运行效率(可能需要调用构造函数),又占用内存。所以在我们开发的过程中,大伙也需要对这个问题稍微有所了解。特别说明:临时对象是要考虑生存期的,就好比假设我们用一个引用来指向一个return出来的临时对象,return语句一结束,临时对象就没了,这个时候就是个悬空引用了,之后在去用这个引用就会引发一些不可预估的行为(当然对于这种错误笔者相信编译的时候应该会有相应的warning会报出来吧???)。对于这种生存期的问题我们在代码中切记留个心眼。

笔者还未弄清的问题?

1.临时对象分全局和局部的吗?就好比说我在全局写:test A = 2, 和在函数内部写有什么区别?如果分,那么全局和局部的临时对象的生存期分别是多久?

笔者猜测:针对 test A =2, 无论全局还是局部在临时对象作为参数初始化对象A之后,这个temp对象应该会立即“消失”。对于全局的,会被编译器优化,对于局部的A的构造函数运行起来之后,temp作为参数完成其任务之后就会从栈上消失。但是函数运行起来之后每个函数都有自己的栈空间,函数没有return的话,栈空间也不会消失啊?所以temp应该要等到函数return之后才会消失吧????

2.return的值怎么返回到调用函数的局部变量?

如:int func (){int B=1;return B;}

void main() { int A = func;}

A的赋值是func函数的栈空间被释放前还是释放后?这个赋值过程怎么理解?

笔者猜测1:return的时候B的值被存在某个寄存器,然后func的栈空间被释放,函数返回到赋值语句,赋值语句将寄存器存的B的值给变量A?但是对于类对象,对于返回临时大数组元素(暂且不考虑代码规范问题),这个猜测不成立,寄存器可能放不下这么大的元素。

笔者猜测2:return之后func的栈空间没有立马释放,而是将赋值语句执行之后才释放,对于小元素直接将栈上的值赋给main空间变量,对于大的原色(如大数组)返回一个指针和长度,然后执行mempy??

对于以上两个问题,可能是笔者还有很多基础指示不扎实,希望寻求答案!!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值