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 ...
随机推荐
- jQuery+turn.js翻书、文档和杂志3种特效演示
很好用的一款插件jQuery+turn.js翻书.文档和杂志3种特效演示 在线预览 下载地址 实例代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML ...
- 【CSS3】css3:box-sizing属性
本文介绍了css3中的box-sizing属性,在这之前读者需要预备知识width的范围. 浏览器的支持情况 Browser Suppored Notes Internet Explorer Yes ...
- 【初探HTML本相】道之真谛不过自然,html标签脱俗还真
前言 须弥般若有无空,阴阳道化真虚同:洗尽前恩本非相,还吾面目下九重. 咳咳,其实老夫对佛教文化有点点研究啦,说以我们这里来了一点很有哲理的东西,因为我这里准备干一件很戳的事情,我准备来看看我们的ht ...
- 常让人误解的一道js小题
一道小题引发的深思 今天无意中看到一个js笔试题,不由得想起初学js那会被各种题目狂虐的心酸,虽说现在也会被笔试题所虐,但毕竟比之前好了很多,下面就是我的个人理解,欢迎拍砖.指正: var x = 1 ...
- 从零开始,做一个NodeJS博客(零):整体规(chui)划(niu)
标签:NodeJS,Heroku 0 搭建一个个人独立博客,这是我好久之前就在计划的一件事了. 这个暑假,我学习了廖雪峰老师的NodeJS教程,又偶然在V2EX上发现了Heroku这个平台,可以免费在 ...
- SAP 使用较频繁的日期时间处理函数总结
在ABAP实际开发中,经常需要用到一些日期时间处理函数,个人感觉经常使用到的函数进行一下汇总 1. 根据工厂日历 计划交货日期 和 收货处理时间 来计算 销售计划中计划完工日期,其他类似日期计算等 ...
- Android Handler机制(一)---Message源码分析
Message: 定义: public final class Message implements Parcelable Message类是个final类,就是说不能被继承,同时Message类实现 ...
- Ubuntu 安装WPS
1.到官网下载deb安装包 http://community.wps.cn/download/ 2.安装 sudo dpkg -i wps-office_10.1.0.5672~a21_amd64.d ...
- swift学习之UI控件(一)
// // ViewController.swift // test // // Created by chuangqu on 15/7/23. // Copyright (c) 2015年 ...
- java "".split(",")
String[] string = "".split(","); 结果是string = []; String[] string = " " ...