对象作为返回值,与基本数据类型不同.基本数据类型(浮点类型以及非标准的__int64类型除外)作为返回值,通过寄存器eax来保存返回的数据,而对象属于自定义类型,寄存器eax无法保存对象中的所有数据,所以在函数返回时,寄存器eax不能满足需求
对象作为返回值与对象作为参数的处理方式非常类似.对象作为参数时,进入函数前预先将对象使用的栈空间保留出来,并将实参对象中的数据复制到栈空间中.该栈空间作为函数参数,用于函数内部使用.
同理,对象作为函数返回值时,进入函数后将申请返回对象使用的栈空间,在退出函数时,将返回对象中的数据复制到临时的栈空间中,以这个临时栈空间的首地址作为返回值.
下面来看一个简单的例子:
调试运行-反汇编窗户中查看:
在看看GetCReturn函数的反汇编
上面演示了函数返回对象的全过程,在调用GetCReturn前,编译器将在main函数中申请的返回对象的首地址作为参数压栈,在函数GetCReturn调用结束后进行了数据复制,将GetCReturn函数中定义的局部变量RetObj的数据复制到这个返回对象的空间中,在将这个返回的对象复制给目标对象objA,从而达到返回对象的目的.因为在这个示例中不存在函数返回后为对象的引用赋值,所以这里的返回对象是临时存在的,也就是C++中的临时对象,作用域仅限于单条语句.
为什么会产生这个临时对象呢? 因为调用返回对象的函数时,C++程序员可能采用这个类写法,如GetCReturn.m_nNumber,这只是针对返回对象的操作,而此时函数已经退出,其栈帧也被关闭.函数退出后去操作局部对象显然不适合,因此只能由函数的调用方准备空间,建立临时对象,然后将函数中的局部对象复制给临时对象,在把这个临时对象交给调用方去操作.
本例中obA = GetCReturn();是个赋值运算,由于赋值时GetCReturn函数已经退出,其栈空间已经关闭,同理objA不能直接和函数内局部对象做赋值运算,因此需要临时对象记录返回值以后再来参与赋值.