c++js 构造函数返回值有返回值吗

构造函数有返回值的。。
#include &iostream.h&
B( int nData = 0)
m_nData = nD
cout && &B()& &&
int main(int argc, char* argv[])
B theB = theA.B::B(10);
代码如上,我认为有 大家说下------解决方案--------------------
标准都规定没有了。
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 12345678910 Copyright & &&版权所有反汇编C++之构造函数篇 - 看雪安全论坛
『软件调试逆向』 [综合性论坛]本版讨论的主题包括:调试逆向、系统底层、商业保护、虚拟机保护、.NET平台等安全相关的话题。
该主题: "反汇编C++之构造函数篇" 因在一定的时间里没有任何回复而自动关闭。如果您还对该主题感兴趣或者想参与对此主题的讨论,请您重新发表一篇相关的新主题。
注册日期: Apr 2012
现金: 4 Kx
获感谢文章数:2获会员感谢数:5
, 18:21:09
反汇编C++之构造函数篇
在类的对象创建的时候,构造函数起到了对对象的初始化的作用。本节将对构造函数的机理进行探讨。可以思考下面的几个问题:1、构造函数的用到是什么机制?2、构造函数在汇编形式下有什么特点,也即是怎样在汇编代码中识别构造函数?由于存在不同生命周期、不同作用域的对象,那么这些构造函数的实现机制都是相同的么?
带着这样的疑问,我们来使用实际的例子探究一番。
本节实验环境:VC++&2013
#include&&iostream&
using&namespace&
class&Rectangle{
&&&&int&width&;
&&&&int&height&;
&&&&Rectangle();
Rectangle::Rectangle&(int&width&,&int&height)
&&&&this.width&=&width&;
&&&&this.height&=&height&;
void&main()
&&&&Rectangle&t&(3,&6);
在debug模式下查看其main函数的反汇编代码:
void&main()
00D75300&&push&&&&&&&&ebp&
00D75301&&mov&&&&&&&&&ebp,esp&
00D75303&&sub&&&&&&&&&esp,0D4h&&
00D75309&&push&&&&&&&&ebx&
00D7530A&&push&&&&&&&&esi&
00D7530B&&push&&&&&&&&edi&
00D7530C&&lea&&&&&&&&&edi,[ebp+FFFFFF2Ch]&
00D75312&&mov&&&&&&&&&ecx,35h&&
00D75317&&mov&&&&&&&&&eax,0CCCCCCCCh&&
00D7531C&&rep&stos&&&&dword&ptr&es:[edi]&
00D7531E&&mov&&&&&&&&&eax,dword&ptr&ds:[00D7F000h];该行以及下面两行是检测栈是否被修改策略用到的方法,先不用追究。
00D75323&&xor&&&&&&&&&eax,ebp&
00D75325&&mov&&&&&&&&&dword&ptr&[ebp&-4],&eax&
&&&&Rectangle&t&(3,&6&);
00D75328&&push&&&&&&&&6&
00D7532A&&push&&&&&&&&3&
00D7532C&&lea&&&&&&&&&ecx,[ebp-10h];ebp-10h是变量t的首地址,即是该对象的this指针&
00D7532F&&call&&&&&&&&00D712B2&
需要注意的是,在栈帧的建立过程中,需要遵守x86的函数调用约定,将callee保存的寄存器压入栈内。
callee保存的寄存器值:ebx、esi、edi.可以发现这个函数调用将callee需要保存的寄存器全部保存起来。
在创建对象的时候,下面的代码即是调用构造函数的代码:
00D75328&&push&&&&&&&&6&
00D7532A&&push&&&&&&&&3&
00D7532C&&lea&&&&&&&&&ecx,[ebp-10h]&&
00D7532F&&call&&&&&&&&00D712B2&
其中lea&ecx,[ebp-10h]值得注意,ecx保存的值相当于就是this指针,也就是说调用构造函数也要传递this指针了。其实,识别C++类的比较好的方法是,C++的成员函数的this指针都是通过ecx寄存器传递的。
回到代码中,可以发现在构造函数调用前,会腾出一段栈空间(ebp-10到ebp之间的空间)提供给对象使用。
在执行到call函数之后,进行单步调试,会进入到一个jmp指令:
00D712B2&&jmp&&&&&&&&&00D73030&
之后进入构造函数进行执行:
Rectangle::Rectangle&(int&width,&int&height)
00D73030&&push&&&&&&&&ebp&
00D73031&&mov&&&&&&&&&ebp,esp&
00D73033&&sub&&&&&&&&&esp,0CCh&&
00D73039&&push&&&&&&&&ebx&
00D7303A&&push&&&&&&&&esi&
00D7303B&&push&&&&&&&&edi&
00D7303C&&push&&&&&&&&ecx&
00D7303D&&lea&&&&&&&&&edi,[ebp+FFFFFF34h]&
00D73043&&mov&&&&&&&&&ecx,33h&&
00D73048&&mov&&&&&&&&&eax,0CCCCCCCCh&&
00D7304D&&rep&stos&&&&dword&ptr&es:[edi]&
00D7304F&&pop&&&&&&&&&ecx&
00D73050&&mov&&&&&&&&&dword&ptr&[ebp&-8],&将this指针保存到地址为ebp-8的内存呢
&&&&this-&&width&=&width&;
00D73053&&mov&&&&&&&&&eax,dword&ptr&[&ebp-8&];将this指针传递到eax&&
00D73056&&mov&&&&&&&&&ecx,dword&ptr&[&ebp+8&];将参数width传递给ecx
00D73059&&mov&&&&&&&&&dword&ptr&[eax&],对this指针所指对象的第一个变量进行赋值
&&&&this-&&height&=&height&;
00D7305B&&mov&&&&&&&&&eax,dword&ptr&[&ebp-8&]&
&&&&this-&&height&=&height&;
00D7305E&&mov&&&&&&&&&ecx,dword&ptr&[&ebp+0Ch&];获取参数height&&
00D73061&&mov&&&&&&&&&dword&ptr&[eax&+4],&ecx&;对this指针所指对象的第二个变量进行赋值
00D73064&&mov&&&&&&&&&eax,dword&ptr&[&ebp-8&];eax保存了this指针,&&
00D73067&&pop&&&&&&&&&edi&
00D73068&&pop&&&&&&&&&esi&
00D73069&&pop&&&&&&&&&ebx&
00D7306A&&mov&&&&&&&&&esp,ebp&
00D7306C&&pop&&&&&&&&&ebp&
00D7306D&&ret&&&&&&&&&8&
注意此代码中ecx在函数最前面要使用一堆数据填充栈时需要用到ecx,所有先保存起来,后来再使用,所以有压栈和弹栈的过程。通过上面的代码我们可以知道,对成员变量的赋值,其实都是通过this指针进行索引,间接寻址方式找到成员变量,也可以看出隐含着的this指针作用多么重要。另外,虽然我们写构造函数时没有返回值,但在汇编代码中还体现了构造函数“拥有”返回值这一现象,即通过eax构造函数返回了this指针,这些隐藏于代码之下的细节,也只有通过汇编的形式才能看到。
上面的对象作为局部对象,是在栈空间内存储对象的数据成员的。
那么,作为在main函数执行之前就已经存在的全局对象和静态对象,在什么时候调用构造函数的呢?
Rectangle&my(5&,&7&);
void&main()
注:Rectangle类与例1中的定义相同。
直接在Rectangle&my&(5&,&7&)处下断点,将会到下面的地方执行:
00AC19B0&&push&&&&&&&&ebp&
00AC19B1&&mov&&&&&&&&&ebp,esp&
00AC19B3&&sub&&&&&&&&&esp,0C0h&&
00AC19B9&&push&&&&&&&&ebx&
00AC19BA&&push&&&&&&&&esi&
00AC19BB&&push&&&&&&&&edi&
00AC19BC&&lea&&&&&&&&&edi,[ebp-0C0h]&&
00AC19C2&&mov&&&&&&&&&ecx,30h&&
00AC19C7&&mov&&&&&&&&&eax,0CCCCCCCCh&&
00AC19CC&&rep&stos&&&&dword&ptr&es:[edi]&
00AC19CE&&push&&&&&&&&7&
00AC19D0&&push&&&&&&&&5&
00AC19D2&&mov&&&&&&&&&ecx,0ACF324h&&
00AC19D7&&call&&&&&&&&Rectangle&::Rectangle&(0AC12B2h)&
00AC19DC&&pop&&&&&&&&&edi&
00AC19DD&&pop&&&&&&&&&esi&
00AC19DE&&pop&&&&&&&&&ebx&
00AC19DF&&add&&&&&&&&&esp,0C0h&&
00AC19E5&&cmp&&&&&&&&&ebp,esp&
00AC19E7&&call&&&&&&&&__RTC_CheckEsp&(0AC12DAh)&
00AC19EC&&mov&&&&&&&&&esp,ebp&
00AC19EE&&pop&&&&&&&&&ebp&
00AC19EF&&ret&
前面的过程依然是栈帧的建立,着重看后面调用构造函数的代码:&
00AC19CE&&&push&&&&&&&&7&
00AC19D0&&&push&&&&&&&&5&
00AC19D2&&&mov&&&&&&&&&ecx&,0ACF324h&;传递this指针
00AC19D7&&&call&&&&&&&&Rectangle&::&Rectangle&(0AC12B2h&)&
注意到此时传递的this指针并不是在栈上的,而是编译器分配的一个地址,而且这个地址处在虚拟内存中的低地址部分。那么是谁调用了该构造函数呢?我们继续执行,直到该段代码的ret。
当创建堆对象时,又会进行怎样的处理呢?
void&main()
&&&&Rectangle&*&t&=&new&Rectangle(3&,&4&);
汇编代码部分:
Rectangle&*&t&=&new&Rectangle(3,&4);
00E97E7D&&push&&&&&&&&8&
00E97E7F&&call&&&&&&&&operator&new&(0E9137Ah);在堆上申请8个字节的空间&&
00E97E84&&add&&&&&&&&&esp,4&&
00E97E87&&mov&&&&&&&&&dword&ptr&[ebp&-0E0h],&将申请到的空间首地址拿到栈上&&
00E97E8D&&mov&&&&&&&&&dword&ptr&[ebp&-4],&0&
00E97E94&&cmp&&&&&&&&&dword&ptr&[ebp&-0E0h],&0;检查返回的地址是不是NULL.即有没有申请成功&&
00E97E9B&&je&&&&&&&&&&main&+74h&(0E97EB4h&);申请空间失败,则不调用构造函数&&
00E97E9D&&push&&&&&&&&4&
00E97E9F&&push&&&&&&&&3&
00E97EA1&&mov&&&&&&&&&ecx,dword&ptr&[&ebp-0E0h&];this指针传入&&
00E97EA7&&call&&&&&&&&Rectangle&::Rectangle&(0E912B2h)&;调用构造函数
00E97EAC&&mov&&&&&&&&&dword&ptr&[ebp&-0F4h],&返回的this指针保存
00E97EB2&&jmp&&&&&&&&&main&+7Eh&(0E97EBEh&)&
00E97EB4&&mov&&&&&&&&&dword&ptr&[ebp&-0F4h],&0;申请空间失败,指针赋值为空&&
00E97EBE&&mov&&&&&&&&&eax,dword&ptr&[&ebp-0F4h&];得到该对象的地址
00E97EC4&&mov&&&&&&&&&dword&ptr&[ebp&-0ECh],&eax&;保存
00E97ECA&&mov&&&&&&&&&dword&ptr&[ebp&-4],&0FFFFFFFFh&
00E97ED1&&mov&&&&&&&&&ecx,dword&ptr&[&ebp-0ECh&];再将对象的首地址移到ecx中&&
00E97ED7&&mov&&&&&&&&&dword&ptr&[t],ecx&&;获取到对象首地址。
通过上面的代码,可以观察到:堆对象创建时,会首先使用new函数申请堆空间,如果申请成功,则执行构造函数,返回首地址,如果不成功,则不执行构造函数,返回为空。既然该指针为空,那么可以想象得到,如果此时引用成员函数,并且访问了该类的动态成员变量,就会引发段错误。
C++拷贝构造函数(浅拷贝)可能带来的问题:
#include&&string.h&
#include&&stdlib.h&
class&CStudent
&&&&char*&
&&&&CStudent(int&m_id,&char*&m_name&);
&&&&CStudent(CStudent&&stu);
&&&&~CStudent&();
CStudent::CStudent&(int&m_id,&char*&m_name&)
&&&&this-&id&=&m_
&&&&int&length&=&strlen(m_name);
&&&&this-&name&=&new&char&[length&+&sizeof(char)];
&&&&strncpy_s(this&-&name,&length+sizeof(char),&m_name,&length&);
CStudent::~CStudent&()
&&&&delete&&this&-&
&&&&this-&name&=&NULL&;
CStudent::CStudent&(CStudent&&stu)
&&&&this-&id&=&stu.&
&&&&this-&name&=&stu.&
void&main()
&&&&&&&&&&&&&&&&&CStudent&stu(1,&&bingxian&&);
&&&&&&&&&&&&&&&&&CStudent&stu2(stu);
执行上面的程序,就会出现错误。
其原因是析构函数会释放掉字符串资源,而st1和st2两个对象共享了name资源,析构的时候就会两次释放该资源,于是导致了错误。所以,在编写拷贝构造函数时,为了避免出现这样的错误发生,应使用深度拷贝构造函数。
上面的例子稍加改动拷贝构造函数即可:
CStudent::CStudent(CStudent&&stu)
&&&&&&&&&&&&&&&&&this-&id&=&stu&.
&&&&&&&&&&&&&&&&&int&length&=&strlen(stu&.name);
&&&&&&&&&&&&&&&&&this-&name&=new&char&&[length&+&sizeof(char&)];/*在堆上开辟一段缓冲区*/
&&&&&&&&&&&&&&&&strncpy_s(&this-&name,&length+sizeof&(char),&stu.name,&length);/*将字符串copy到申请的缓冲区中*/
&&&&&&&&&&&&&&&&&/*this-&name&=&stu.*/
我们需要分析的参数对象产生时的汇编形式,看看拷贝构造函数被调用时发生了什么:
&&&&CStudent&stu2&(stu)&;
00E71680&&push&&&&&&&&8&
00E71682&&lea&&&&&&&&&ecx,[stu2&]&
00E71685&&call&&&&&&&&CStudent&::__autoclassinit2&(0E711E0h)&
00E7168A&&lea&&&&&&&&&eax,[stu&]&
00E7168D&&push&&&&&&&&eax&
00E7168E&&lea&&&&&&&&&ecx,[stu2&]&
00E71691&&call&&&&&&&&CStudent&::CStudent&(0E710FAh)&&
可以看到,编译器会首先为stu2分配8字节的栈空间,并且做初始化工作,接着使用stu对象作为参数传递到构造函数中。
我们为上面的例子中加一个函数:
void&InforStu(CStudent&stu)
&&&&&&&&&&&&&&&&cout&&&&id&=&&&&&&stu&.id&&&&
&&&&&&&&&&&&&&&&cout&&&&&name:&&&&&stu&.name&&&&
这个函数将CStudent对象作为参数,那么在调用的时候自然会生成对象的拷贝,自然会调用拷贝构造函数,来看一下反汇编代码:
&&&&InforStu(stu2&);
003262CA&&sub&&&&&&&&&esp,8&&
003262CD&&mov&&&&&&&&&ecx,新对象的this指针
003262CF&&mov&&&&&&&&&dword&ptr&[ebp&-0F8h],&esp&
&&lea&&&&&&&&&eax,[stu2&];stu2对象&&
&&push&&&&&&&&eax&
&&call&&&&&&&&CStudent&::CStudent&(032123Fh);调用拷贝构造函数
003262DE&&mov&&&&&&&&&dword&ptr&[ebp&-100h],&eax&;返回this指针
&&call&&&&&&&&InforStu&(0321005h)&&
从反汇编代码中可以看到,编译器会在栈底弄出一部分空间,使用拷贝构造函数新建一个对象,函数会使用这个新建的对象作为参数。
被 浪子wj 最后编辑
共 4 位会员感谢 浪子wj 发表的文章:
&(), &(), &(), &()
注册日期: Nov 2014
现金: 100 Kx
获感谢文章数:11获会员感谢数:20
, 20:39:51
学习了&&很仔细&谢谢!
注册日期: Nov 2008
现金: 227 Kx
获感谢文章数:0获会员感谢数:0
, 23:29:55
注册日期: Mar 2012
现金: 2 Kx
致谢数: 16
获感谢文章数:0获会员感谢数:0
, 11:53:51
堆对象创建时,会首先使用new函数申请堆空间,如果申请成功,则执行构造函数,返回首地址,如果不成功,则不执行构造函数,返回为空。既然该指针为空,那么可以想象得到,如果此时引用成员函数,就会引发段错误。
楼主这段话不准确,指针为空可以引用成员函数的,只要成员函数里面不访问成员变量就不会有问题,这种情况如果引发错误是因为成员函数访问了成员变量
注册日期: Apr 2012
现金: 4 Kx
获感谢文章数:2获会员感谢数:5
, 16:15:00
最初由 holysh发布
楼主这段话不准确,指针为空可以引用成员函数的,只要成员函数里面不访问成员变量就不会有问题,这种情况如果引发错误是因为成员函数访问了成员变量
谢谢指正,已改正。
注册日期: Oct 2013
现金: 70 Kx
获感谢文章数:0获会员感谢数:0
, 09:41:18
学习了,感谢楼主啊,分析的很仔细,再次感谢
注册日期: Aug 2010
现金: 451 Kx
获感谢文章数:7获会员感谢数:8
, 10:05:23
c++是高级语言,才有对对象,封装的概念,每个函数有其层次结构,每个类都有其父代模型,这是认为的建立一种层次逻辑结构,便于人类进行编程,归类,但是汇编语言是面向机器的,c++经过编译以后,就没有任何层次结构了,湖边语言里面各种函数都是平行关系,互相call来call去真的是错综复杂,根本理不清楚。
注册日期: Mar 2014
现金: 0 Kx
获感谢文章数:0获会员感谢数:0
, 11:16:10
感谢楼主的分享
注册日期: Jan 2008
现金: 258 Kx
获感谢文章数:12获会员感谢数:48
, 11:43:19
msvc的this是ecx,gcc是入栈。构造inline的话就是直接把函数实现放在那里,否则就是一个call。
注册日期: Nov 2010
现金: 27 Kx
致谢数: 147
获感谢文章数:0获会员感谢数:0
, 10:56:57
认清了this指针,其他就好办了
注册日期: Mar 2013
现金: 188 Kx
获感谢文章数:1获会员感谢数:1
, 16:03:58
好帖,感谢分享。
注册日期: May 2011
现金: 21 Kx
获感谢文章数:0获会员感谢数:0
, 15:32:01
可以继续分析下初始化列表以及有继承关系的构造
注册日期: Apr 2014
现金: 52 Kx
获感谢文章数:0获会员感谢数:0
, 09:20:59
讲的非常仔细。
该主题: "反汇编C++之构造函数篇" 因在一定的时间里没有任何回复而自动关闭。如果您还对该主题感兴趣或者想参与对此主题的讨论,请您重新发表一篇相关的新主题。
您不可以发表主题
您不可以回复帖子
您不可以上传附件
您不可以编辑自己的帖子
论坛论坛启用
用户控制面板
会员在线状态
CrackMe攻击篇,分析文章提交区
『看雪众测/众包』
『求助问答』
『经典问答』
『资料导航』
『软件调试逆向』
『密码学』
『编程技术』
『C32Asm』
『MDebug』
『安全工具开发』
『加壳与脱壳』
『CrackMe&ReverseMe』
『资源下载』
『Android 安全』
『Android 开发』
『iOS安全』
『WEB安全』
『漏洞分析』
『外文翻译』
『招聘专区』
『职业生涯』
『15PB培训』
『麦洛克菲培训』
『茶余饭后』
『安全资讯』
『论坛活动』
6)PEDIY Crackme竞赛2009
7)看雪十周年专版
8)腾讯公司2010软件安全竞赛
9)2011 Exploit Me竞赛
『图书项目版』
《加密与解密(第三版)》
《C++反汇编与逆向分析技术揭秘》
《Android软件安全与逆向分析》
『论坛版务』
所有时间均为北京时间, 现在的时间是 .
&&& 看雪学院()
| 提供带宽资源
|&微信公众帐号:c++ 中构造函数与一般函数的不同特点是什么有三个不同特点
1.没有返回值2.不可被外部主动调用3.可以默认实现4.可以使用下面写法:a(int c,int d):c(c),d(d){}5.函数名需要和类名相同如果是3个的话,哈哈,建议你选125
为您推荐:
其他类似问题
扫描下载二维码Jhuster 的BLOG
用户名:Jhuster
文章数:157
评论数:393
访问量:1288337
注册日期:
阅读量:5863
阅读量:12276
阅读量:364681
阅读量:1059874
51CTO推荐博文
c++构造函数的知识在各种c++教材上已有介绍,不过初学者往往不太注意观察和总结其中各种构造函数的特点和用法,故在此我根据自己的c++编程经验总结了一下c++中各种构造函数的特点,并附上例子,希望对初学者有所帮助。1. 构造函数是干什么的class&Counter
&&&&//&类Counter的构造函数
&&&&//&特点:以类名作为函数名,无返回类型
&&&&Counter()
&&&&&&&&m_value&=&0;
private:&&&&&
&&&&//&数据成员
}该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数-&由构造函数完成成员的初始化工作eg: Counter c1;& & & &&编译系统为对象c1的每个数据成员(m_value)分配内存空间,并调用构造函数Counter()自动地初始化对象c1的m_value值设置为0故:构造函数的作用:初始化对象的数据成员。2. 构造函数的种类class&Complex&
{&&&&&&&&&
&&&&double&m_
&&&&double&m_
&&&&//&无参数构造函数
&&&&//&如果创建一个类你没有写任何构造函数,则系统会自动生成默认的无参构造函数,函数为空,什么都不做
&&&&//&只要你写了一个下面的某一种构造函数,系统就不会再自动生成这样一个默认的构造函数,如果希望有一个这样的无参构造函数,则需要自己显示地写出来
&&&&Complex(void)
&&&&&&&&&m_real&=&0.0;
&&&&&&&&&m_imag&=&0.0;
&&&&//&一般构造函数(也称重载构造函数)
&&&&//&一般构造函数可以有各种参数形式,一个类可以有多个一般构造函数,前提是参数的个数或者类型不同(基于c++的重载函数原理)
&&&&//&例如:你还可以写一个&Complex(&int&num)的构造函数出来
&&&&//&创建对象时根据传入的参数不同调用不同的构造函数
&&&&Complex(double&real,&double&imag)
&&&&&&&&&m_real&=&
&&&&&&&&&m_imag&=&&&&&&&&&&
&&&&//&复制构造函数(也称为拷贝构造函数)
&&&&//&复制构造函数参数为类对象本身的引用,用于根据一个已存在的对象复制出一个新的该类的对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中
&&&&//&若没有显示的写复制构造函数,则系统会默认创建一个复制构造函数,但当类中有指针成员时,由系统默认创建该复制构造函数会存在风险,具体原因请查询有关&“浅拷贝”&、“深拷贝”的文章论述
&&&&Complex(const&Complex&&&c)
&&&&&&&&//&将对象c中的数据成员值复制过来
&&&&&&&&m_real&=&c.m_
&&&&&&&&m_img&&=&c.m_
&&&&}&&&&&&&&&&&&
&&&&//&类型转换构造函数,根据一个指定的类型的对象创建一个本类的对象
&&&&//&例如:下面将根据一个double类型的对象创建了一个Complex对象
&&&&Complex::Complex(double&r)
&&&&&&&&m_real&=&r;
&&&&&&&&m_imag&=&0.0;
&&&&//&等号运算符重载
&&&&//&注意,这个类似复制构造函数,将=右边的本类对象的值复制给等号左边的对象,它不属于构造函数,等号左右两边的对象必须已经被创建
&&&&//&若没有显示的写=运算符重载,则系统也会创建一个默认的=运算符重载,只做一些基本的拷贝工作
&&&&Complex&&operator=(const&Complex&&rhs)
&&&&&&&&//&首先检测等号右边的是否就是左边的对象本,若是本对象本身,则直接返回
&&&&&&&&if&(&this&==&&rhs&)&
&&&&&&&&&&&&return&*
&&&&&&&&&&&&
&&&&&&&&//&复制等号右边的成员到左边的对象中
&&&&&&&&this-&m_real&=&rhs.m_
&&&&&&&&this-&m_imag&=&rhs.m_
&&&&&&&&&&&&
&&&&&&&&//&把等号左边的对象再次传出
&&&&&&&&//&目的是为了支持连等&eg:&&&&a=b=c&系统首先运行&b=c
&&&&&&&&//&然后运行&a=&(&b=c的返回值,这里应该是复制c值后的b对象)&&&&
&&&&&&&&return&*
};下面使用上面定义的类对象来说明各个构造函数的用法:void&main()
&&&&//&调用了无参构造函数,数据成员初值被赋为0.0
&&&&Complex&c1,c2;
&&&&//&调用一般构造函数,数据成员初值被赋为指定值
&&&&Complex&c3(1.0,2.5);
&&&&//&也可以使用下面的形式
&&&&Complex&c3&=&Complex(1.0,2.5);
&&&&//&把c3的数据成员的值赋值给c1
&&&&//&由于c1已经事先被创建,故此处不会调用任何构造函数
&&&&//&只会调用&=&号运算符重载函数
&&&&c1&=&c3;
&&&&//&调用类型转换构造函数
&&&&//&系统首先调用类型转换构造函数,将5.2创建为一个本类的临时对象,然后调用等号运算符重载,将该临时对象赋值给c1
&&&&c2&=&5.2;
&&&&//&调用拷贝构造函数(&有下面两种调用方式)&
&&&&Complex&c5(c2);
&&&&Complex&c4&=&c2;&&//&注意和&=&运算符重载区分,这里等号左边的对象不是事先已经创建,故需要调用拷贝构造函数,参数为c2&&&&&&&
}3. 思考与测验(1) 为什么函数中可以直接访问对象c的私有成员 ?Complex(const&Complex&&&c)
&&&&//&将对象c中的数据成员值复制过来
&&&&m_real&=&c.m_
&&&&m_img&=&c.m_
}(2) 挑战题,了解引用与传值的区别Complex&test1(const&Complex&&c)
&&&&return&c;
Complex&test2(const&Complex&c)
&&&&return&c;
Complex&test3()
&&&&static&Complex&c(1.0,5.0);
&&&&return&c;
Complex&&test4()
&&&&static&Complex&c(1.0,5.0);
&&&&return&c;
void&main()
&&&&Complex&a,b;
&&&&//&下面函数执行过程中各会调用几次构造函数,调用的是什么构造函数?
&&&&test1(a);
&&&&test2(a);
&&&&b&=&test3();
&&&&b&=&test4();
&&&&test2(1.2);
&&&&//&下面这条语句会出错吗?
&&&&test1(1.2);&&&&&
&&&&//test1(&Complex(1.2&))&呢?
}4. 浅拷贝与深拷贝上面提到,如果没有自定义复制构造函数,则系统会创建默认的复制构造函数,但系统创建的默认复制构造函数只会执行“浅拷贝”,即将被拷贝对象的数据成员的值一一赋值给新创建的对象,若该类的数据成员中有指针成员,则会使得新的对象的指针所指向的地址与被拷贝对象的指针所指向的地址相同,delete该指针时则会导致两次重复delete而出错。下面是示例:#include&&iostream.h&
#include&&string.h&
class&Person&
&&&&//&构造函数
&&&&Person(char&*&pN)
&&&&&&&&cout&&&&"一般构造函数被调用&!\n";
&&&&&&&&m_pName&=&new&char[strlen(pN)&+&1];
&&&&&&&&//在堆中开辟一个内存块存放pN所指的字符串
&&&&&&&&if(m_pName&!=&NULL)&
&&&&&&&&&&&//如果m_pName不是空指针,则把形参指针pN所指的字符串复制给它
&&&&&&&&&&&&&strcpy(m_pName&,pN);
&&&&}&&&&&&&&
&&&&//&系统创建的默认复制构造函数,只做位模式拷贝
&&&&Person(Person&&&p)&&&&
&&&&&&&&//使两个字符串指针指向同一地址位置&&&&&&&&&
&&&&&&&&m_pName&=&p.m_pN&&&&&&&&&
&&&&~Person(&)
&&&&&&&&delete&m_pN
&&&&char&*&m_pN
void&main(&)
&&&&Person&man("lujun");
&&&&Person&woman(man);&
&&&&//&结果导致&&&man&和&&&&woman&的指针都指向了同一个地址
&&&&//&函数结束析构时
&&&&//&同一个地址被delete两次
//&下面自己设计复制构造函数,实现“深拷贝”,即不让指针指向同一地址,而是重新申请一块内存给新的对象的指针数据成员
Person(Person&&&chs);
&&&&&//&用运算符new为新对象的指针数据成员分配空间
&&&&&m_pName=new&char[strlen(p.m_pName)+&1];
&&&&&if(m_pName)&&&&&&&&&
&&&&&&&&&&&&&//&复制内容
&&&&&&&&&&&&strcpy(m_pName&,chs.m_pName);
&&&&//&则新创建的对象的m_pName与原对象chs的m_pName不再指向同一地址了
}本文出自 “” 博客,请务必保留此出处
了这篇文章
类别:┆阅读(0)┆评论(0)
22:49:08 02:28:02

我要回帖

更多关于 c 构造函数 返回值 的文章

 

随机推荐