【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
拷贝构造函数和复制函数是类里面比较重要的两个函数。两者有什么区别呢?其实也很简单,我们可以举个例子,加入有这样一个类的定义:
class apple
{
public:
apple() { printf("apple()!\n");}
apple(apple& a) { printf("copy apple()!\n");}
apple& operator=(apple& a) { printf("= apple()\n"); return *this;}
~apple() { printf("~apple()!\n");}
void print() const { return;}
};
那么我们在如下的函数里面进行调用的时候,调用的函数分别是哪些呢?
void process()
{
apple a, c;
apple b =a;
c = b;
}
其实汇编的结果是这样的,大家可以一起看一下,自己尝试读一下。如果一次不是很明白,可以多读几次。
70: apple a, c;
0040127D lea ecx,[ebp-10h]
00401280 call @ILT+70(apple::apple) (0040104b)
00401285 mov dword ptr [ebp-4],0
0040128C lea ecx,[ebp-14h]
0040128F call @ILT+70(apple::apple) (0040104b)
00401294 mov byte ptr [ebp-4],1
71: apple b =a;
00401298 lea eax,[ebp-10h]
0040129B push eax
0040129C lea ecx,[ebp-18h]
0040129F call @ILT+50(apple::apple) (00401037)
004012A4 mov byte ptr [ebp-4],2
72: c = b;
004012A8 lea ecx,[ebp-18h]
004012AB push ecx
004012AC lea ecx,[ebp-14h]
004012AF call @ILT+75(apple::operator=) (00401050)
73: }
004012B4 mov byte ptr [ebp-4],1
004012B8 lea ecx,[ebp-18h]
004012BB call @ILT+0(apple::~apple) (00401005)
004012C0 mov byte ptr [ebp-4],0
004012C4 lea ecx,[ebp-14h]
004012C7 call @ILT+0(apple::~apple) (00401005)
004012CC mov dword ptr [ebp-4],0FFFFFFFFh
004012D3 lea ecx,[ebp-10h]
004012D6 call @ILT+0(apple::~apple) (00401005)
004012DB mov ecx,dword ptr [ebp-0Ch]
004012DE mov dword ptr fs:[0],ecx
004012E5 pop edi
004012E6 pop esi
004012E7 pop ebx
004012E8 add esp,58h
004012EB cmp ebp,esp
004012ED call __chkesp (004087c0)
004012F2 mov esp,ebp
004012F4 pop ebp
004012F5 ret
代码有点长,大家可以一句一句来看,比如说就按照70、71、72、73分别查看对应的汇编代码:
(1)70句: 我们看到函数做了两次函数调用,恰好就是apple的构造函数调用。这也正好对应着两个临时变量a和c,两个变量的地址分别是【ebp-10】和【ebp-14】,这里也可以看出整个类的大小就是4个字节,就是一块存放数据的普通内存。而构造函数之所以能和对应的内存绑定在一起,主要是因为ecx记录了内存的起始地址,这在C++编译中是十分关键的。我们看到的C++构造函数好像是没有绑定内存,实际上在VC里面已经做好了约定,ecx就是this指针,就是类的内存起始地址。有兴趣的同学看看G++编译的时候,采用的this指针是哪个寄存器保存的?(其实是eax)
(2)71句:通过对应看到了eax记录了引用变量的地址,而ecx是ebp下面紧挨着四个字节。但是函数调用的地址和前面的缺省构造函数不太一样,所以我们大胆猜测,这里的构造函数这是拷贝构造函数,我们可以在调试的时候查看一下打印消息。
(3)72句:0x4012AF语句已经清楚地告诉了我们,这里调用的函数就是operator=函数,这一部分是算术符重载的内容,我们在后面的博客会重点介绍。
(4)73句: 前面我们讲过,析构函数在函数调用结束的时候被被自动调用,那么这里我们看到却是出现了三个调用?这三个变量正好是我们之前说的a、b、c三个变量。那么这三个变量调用的次序是怎样的呢?我们可以查看一下变量的地址,分别是【ebp-18h】、【ebp-14h】、【ebp-10h】,这正好和变量出现的顺序相反。所以我们看到,析构函数和构造函数是严格一一对应的,谁先出现,谁后析构。
【预告: 下面的博客我们会对构造、析构中出现的一些现象进行总结】
分享到:
相关推荐
1.《从汇编看C++ 之函数开销》 2.《从汇编看C++ 之类成员》 3.《从汇编看C++ 之引用指针动态内存》 4.《从汇编看C++ 之虚函数接口多态》 欢迎大家下载,并到我微博上交流指正,我会继续努力(我微博上也叫小力庭)
用汇编的眼光看C++(之 总结篇)(pdf版本) 网络资源整理版本~~
C++指令字典(汇编,C,C++,VB函数集合及中文说明)简单实用。
C语言 指针
C++虚函数调用的反汇编解析
C++Hook(钩子)编程,通过内联汇编,使类成员函数代替全局函数(静态函数)[收集].pdf
《c++编程思想》上说一个类如果没有拷贝函数,那么编译器会自动创建一个默认的拷贝函数。下面让我们看一下真实的情况。 首先看一个简单的类X,这个类没有显示定义拷贝构造函数。c++源码如下: class X { ...
汇编 入口 函数汇编 入口 函数汇编 入口 函数汇编 入口 函数汇编 入口 函数汇编 入口 函数汇编 入口 函数汇编 入口 函数汇编 入口 函数汇编 入口 函数
在Visual_C++中使用内联汇编 本文档主要详细介绍如何在c/c++代码内涵汇编代码,推荐给学习c/c++的同学们下载
工程主要时C++内联汇编的示例,内部简单的用汇编实现了函数传参及调用,循环以及if语句的实现
c++反汇编 c++反汇编的好教程c++反汇编 c++反汇编的好教程c++反汇编 c++反汇编的好教程
汇编源代码-文件拷贝
多态是C++语言中最重要的特性之一,而虚表以及虚函数是实现多态的重要手段。许多C++语言的教材对于虚函数的使用以及调用机制有着详细的阐述,但是对于虚表的一些细节内容阐述却并不是很深,对于虚表我们可能会有很多...
寄存器 寻址方式 常用汇编指令 C++内联汇编 C++入口函数 反汇编识别main函数 第二讲 整型与浮点型 第三讲 指针与常量 第四讲 布尔型与字符(串) 第五讲 表达式 第六讲 选择结构 第七讲 循环结构 第八讲 变量 第九讲...
c++反汇编中文教程,国外大牛非常经典之作,教你如何用IDA逆向C++。
用于查看c++库文件dll内部函数名称,反汇编工具的一款神奇。 用于查看c++库文件dll内部函数名称,反汇编工具的一款神奇。
汇编 编写一拷贝程序,要求在命令行指定源文件名和目标文件名.
通过挖掘c++编译器源码,深入理解c++语言精粹,有助于深刻掌握c++语言精髓。
在C语言函数中调用汇编语言程序实现字符串的拷贝: 其中:源串:const char *srcstr=“abcdefghij” 目标串:char *dststr
c++中,如果为一个类没有明确定义一个构造函数,那么,编译器就会自动合成一个默认的构造函数。下面,通过汇编程序,来看一下其真实情况