C++浅析——返回对象的函数
一、原码分析
1.1 测试代码
为了方便查看拷贝构造函数调用过程,自定义了拷贝构造函数,但啥也没干。
class CTEST
{
public:
int m_nData; //Method:
public:
CTEST()
{
printf("0x%p CTEST is constructed\n", this);
} CTEST(CTEST& oCtest)
{
printf("0x%p CTEST copy constructor is called, copy object from 0x%p\n", this, &oCtest);
} ~CTEST()
{
printf("0x%p CTEST is destructed\n", this);
}
}; CTEST GetCTest()
{
CTEST oCtest; return oCtest;
} int main(int argc, char* argv[])
{
printf("***************************Test1***************************\n\n");
CTEST oTest1 = GetCTest();
printf("oTest1 address is 0x%p\n", &oTest1);
printf("\n"); printf("***************************Test2***************************\n\n");
CTEST oTest2;
printf("oTest2 address is 0x%p\n", &oTest2);
oTest2 = GetCTest();
printf("\n"); printf("***************************Test3***************************\n\n");
GetCTest();
printf("\n"); getchar();
return 0;
}
运行结果
1.2
CTEST oTest1 = GetCTest();
用返回对象定义赋值对象时,oTest1的构造函数并不会被调用,而是传递其对象的指针作为隐含参数给GetCTest()函数,
GetCTest()会在函数对象返回时调用其拷贝构造函数,利用返回对象对其初始化。
1.3 oTest2 = GetCTest();
用返回对象赋值对象时,与定义赋值不同,并不会传递其对象的指针给GetCTest()函数,而是产生了一个临时对象作为隐含参
数传递给GetCTest()函数,GetCTest()函数执行完毕后,利用临时对象给oTest2对象赋值(即浅拷贝,而不是调用其拷贝构造函数,如
果有资源指针,可能会造成资源泄露,有兴趣的朋友可以深入研究下这个问题)。
1.4 GetCTest();
单独调用GetCTest()函数和1.3类似,也会产生临时对象,只是调用结束后会析构掉。
二、深入分析
2.1 GetCTest()反汇编分析
7: CTEST GetCTest()
8: {
9: CTEST oCtest;
00401074 lea ecx,[ebp-10h]
00401077 call @ILT+5(CTEST::CTEST) (0040100a)
0040107C mov dword ptr [ebp-4],1
10:
11: return oCtest;
00401083 lea eax,[ebp-10h]
00401086 push eax //压入oCtest对象指针
00401087 mov ecx,dword ptr [ebp+8] //取赋值对象的指针,该指针在调用GetCTest()函数时隐式传入
0040108A call @ILT+20(CTEST::CTEST) (00401019) //调用赋值对象的拷贝构造函数
0040108F mov ecx,dword ptr [ebp-14h]
00401092 or ecx,1
00401095 mov dword ptr [ebp-14h],ecx
00401098 mov byte ptr [ebp-4],0
0040109C lea ecx,[ebp-10h]
0040109F call @ILT+15(CTEST::~CTEST) (00401014) //返回对象oCtest析构
004010A4 mov eax,dword ptr [ebp+8] //返回赋值对象的指针
12: }
通过以上反汇编代码的分析,可以看出GetCTest()函数在调用时编译器偷偷摸摸的传入了赋值对象的指针,而返回对象的函数
实际上在返回时已经将返回对象析构了,其返回的是赋值对象的指针,只是在析构前利用返回对象其赋值对象进行拷贝构造了。
2.2 代码反汇编分析
17: CTEST oTest1 = GetCTest();
0040123A lea eax,[ebp-10h]
0040123D push eax //压入oTest1的指针,以供GetCTest拷贝构造对象
0040123E call @ILT+0(GetCTest) (00401005)
00401243 add esp,4
00401246 mov dword ptr [ebp-4],0
18: printf("oTest1 address is 0x%p\n", &oTest1);
0040124D lea ecx,[ebp-10h]
00401250 push ecx
00401251 push offset string "oTest1 address is 0x%p\n" (00427164)
00401256 call printf (004018a0)
0040125B add esp,8 20:
21: printf("***************************Test2***************************\n\n");
0040126B push offset string "***************************Test2"... (00427114)
00401270 call printf (004018a0)
00401275 add esp,4
22: CTEST oTest2;
00401278 lea ecx,[ebp-14h] //调用oTest2的构造函数
0040127B call @ILT+5(CTEST::CTEST) (0040100a)
00401280 mov byte ptr [ebp-4],1
23: printf("oTest2 address is 0x%p\n", &oTest2);
00401284 lea edx,[ebp-14h]
00401287 push edx
00401288 push offset string "oTest2 address is 0x%p\n" (004270f8)
0040128D call printf (004018a0)
00401292 add esp,8
24: oTest2 = GetCTest();
00401295 lea eax,[ebp-1Ch] //压入临时对象的指针
00401298 push eax
00401299 call @ILT+0(GetCTest) (00401005)
0040129E add esp,4
004012A1 mov dword ptr [ebp-28h],eax //保存GetCTest返回的对象地址到[ebp-28h]
004012A4 mov ecx,dword ptr [ebp-28h]
004012A7 mov edx,dword ptr [ecx] //拷贝GetCTest返回的对象的m_nData参数至oTest2对象的m_nData
004012A9 mov dword ptr [ebp-14h],edx
004012AC lea ecx,[ebp-1Ch] //临时对象析构
004012AF call @ILT+15(CTEST::~CTEST) (00401014) 26:
27: printf("***************************Test3***************************\n\n");
004012C1 push offset string "***************************Test3"... (004270ac)
004012C6 call printf (004018a0)
004012CB add esp,4
28: GetCTest();
004012CE lea eax,[ebp-20h] //压入临时对象的指针
004012D1 push eax
004012D2 call @ILT+0(GetCTest) (00401005)
004012D7 add esp,4
004012DA lea ecx,[ebp-20h] //临时对象析构
004012DD call @ILT+15(CTEST::~CTEST) (00401014)
C++浅析——返回对象的函数的更多相关文章
- js创建对象的三种方法:文本标识法和构造器函数法和返回对象的函数
文本标识法和定义变量差不多,像这样 var obj = {name:'HanMM','2':'Dali'}; 函数构造器法 先创建一个对象函数 function Obj() { this.addre ...
- javascript 对象初探(二)--- 返回对象的函数
除了使用new操作符调用构造函数以外,我们也可以抛开new操作符,只用一般函数来创建对象,这样就能执行某些预备工作,并已对象为返回值的函数.. function her(){ return { nam ...
- JavaScript (JS) 面向对象编程 浅析 (含对象、函数原型链、闭包解析)
1. 构造函数原型对象:prototype ① 构造函数独立创建对象,消耗性能 function Person(name) { this.name = name; this.sayHello = fu ...
- c++怎样让返回对象的函数不调用拷贝构造函数
我们知道拷贝构造函数有两种“默默”的方式被调用 1. 想函数传入 值参数 2. 函数返回 值类型 今天我们讨论函数返回值类型的情况. 得到结论是 1. 当对象有拷贝构造函数(系统为我们生成.或者我们自 ...
- 孤荷凌寒自学python第十九天python函数嵌套与将函数作为返回对象及闭包与递归
孤荷凌寒自学python第十九天python函数嵌套与将函数作为返回对象及闭包与递归 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) Python函数非常的灵活,今天学习了python函数的以 ...
- c++逆向分析----返回对象
对象不使用默认析构函数 class Test { public: char cNum1; int iNum2; int* pInt; }; Test _ReturnObject() { Test st ...
- 基类中定义的虚函数在派生类中重新定义时,其函数原型,包括返回类型、函数名、参数个数、参数类型及参数的先后顺序,都必须与基类中的原型完全相同 but------> 可以返回派生类对象的引用或指针
您查询的关键词是:c++primer习题15.25 以下是该网页在北京时间 2016年07月15日 02:57:08 的快照: 如果打开速度慢,可以尝试快速版:如果想更新或删除快照,可以投诉快照. ...
- STL算法设计理念 - 函数对象和函数对象当参数和返回值
函数对象: 重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象.一个类对象,表现出一个函数的特征,就是通过"对象名+(参数列表)&qu ...
- oracle 用函数返回对象集合
1.先要声明全局type:并且,字段变量类型要为object,不能为record: (1)CREATE OR REPLACE TYPE "DDD_BY_DEPT_STATISTISC&quo ...
随机推荐
- Lazyr.js – 延迟加载图片(Lazy Loading)
Lazyr.js 是一个小的.快速的.现代的.相互间无依赖的图片延迟加载库.通过延迟加载图片,让图片出现在(或接近))视窗才加载来提高页面打开速度.这个库通过保持最少选项并最大化速度. 在线演示 ...
- React Native – 使用 JavaScript 开发原生应用
前不久,Facebook 在F8开发者大会上正式开源了 React Native 项目.不过目前只有 iOS 版,Android 版还需要再等一段时间,这是最新的用 JavaScript 语言开发原生 ...
- Pizza Pie Charts – 基于 Snap SVG 框架的响应式饼图
Pizza Pie Charts 是一个基于 Adobe 的 Snap SVG 框架的响应式饼图插件.它着重于集成 HTML 标记和 CSS,而不是 JavaScript 对象,当然Pizza Pie ...
- Subway Icon Set – 306个像素完美的特制图标
这个图标集是306个优化的像素完美,精雕细琢的图标.为这些设备进行了优化:iOS.Windows Phone.Windows 8 and BlackBerry 10,提供 PNG, SVG, XALM ...
- 高性能javascript学习笔记系列(2)-数据存取
参考 高性能javascript Tom大叔深入理解javascript系列 相关概念 1.执行上下文 当控制器转到ecmascript可执行代码的时候,就会进入一个执行上下文,执行上下文是以堆栈 ...
- sass菜鸟教程
1.安装sass 在安装sass前需要安装ruby,下载ruby时要注意自己电脑是32位还是64位,下载好正常安装,但注意一下:要勾选下图这一项,添加环境变量(安装过JDK的朋友应该知道环境变量) 下 ...
- js资源加载优化
互联网应用或者访问量大的应用,对js的加载优化是不可少的.下面记录几种优化方法 CDN + 浏览器缓存 CDN(content delivery network)内容分发网络, 最传统的优化方式.其 ...
- 对于Access数据库查询遇到空值的解决办法
1.Access数据库在office环境下对于null是识别的,但是,在开发环境下,Access数据库对于where xxx is null是不识别的. 2.查询空值解决办法:select * fro ...
- NDK-JNI实战教程(二) JNI官方中文资料
声明 设计概述 JNI接口函数和指针 加载和链接本地方法 解析本地方法名 本地方法的参数 引用Java对象 全局和局部引用 实现局部引用 访问Java对象 访问基本类型数组 访问域和方法 报告编程错误 ...
- JSON 转javabean 利器
别再对着json来手写javabean啦.这个工作完全不要脑子,而且耗时. 这里给大家提供三种方式: android studio版: 万能的插件:GsonFormat 如何安装? Preferenc ...