为什么有的运算符重载返回值,返回值要为引用

面试题(16)
引用网址:/zjf_to/blog/static//
#include &iostream&
#include &string.h&
class CMessage {
CMessage(char* MessageText = &Default Text!&) {
cout&&&Constructor called!&&&
Message = new char[strlen(MessageText) + 1];
strcpy(Message, MessageText);
void ShowMessage() {
cout&&&The message is &&&Message&&
~CMessage() {
cout&&&Destructor Called!&&&
cout && &Delete data& &&
delete[] M
CMessage& operator =(const CMessage& OtherObject) {
cout && &override assignment operator function& &&
if (this != &OtherObject)//检查对象是否已经赋值给自身
delete [] M
Message = new char[strlen(OtherObject.Message) + 1];
strcpy(Message, OtherObject.Message);
int main(int argc, char* argv[]) {
CMessage message1(&awei is the best!&);
CMessage message2;
CMessage message3(&abcdefadfadf&);
message2 = message1;
message1.ShowMessage();
message2.ShowMessage();
(message1=message2)=message3;
message1.ShowMessage();
message2.ShowMessage();
message3.ShowMessage();
*/return 0;
如果我们不重载赋值运算符,那么类会自动为我们提供一个赋值运算符,这个默认的赋值运算符函数跟默认的复制构造函数是一样的,就是把一个对象的数据成员的值复制给另一个对象对应的数据成员,在做此测试时,我也遇到了一个问题,直接利用默认赋值函数,引发内存溢出的问题,
代码及原因解释如下:
//////////////////////////////////////////////////////////////////////////
&//如果不重载赋值运算符,则下面这条语句
&//messge2 = message1;
&//将出现很低级的错误,因为这样的话两个成员变量message1和message2指针指向同一块内存地址,
&//在程序退出后,第一次调用调用message2的析构函数,则Message指针的地址已经释放,此时再次调用
&//message2的析构函数,即是对同一块内存第二次调用delete,那么将出现内存泄漏现象
&//////////////////////////////////////////////////////////////////////////
那么我们自己重载了赋值运算符,其参数和返回值为什么要非是引用类型不可呢?
我试着将赋值运算符函数的形参改为CMessage对象,此时再次爆发内存错误,原因是:
当我们以CMessage对象作为实参传入函数时,是以按值传递方式进行的,此时在函数内部将创建一个实参的副本,当函数返回时,该实参副本将被自动清除,实参副本中的Message指针将被释放,由于该指针指向的是对象message2的Message变量所指向的地址,因此message2对象的成员变量所指向的地址就这样莫名其妙的消失了,这样的错误编译时无法发现,但是运行时就会发生错误。运行结果为:
Constructor called!
Constructor called!
Destructor Called!
The message is 葺葺葺葺葺葺葺葺葺葺葺葺
The message is awei is the best!
Destructor Called!
Destructor Called!
当把返回类型改为CMessage对象时,此时跟上述情况雷同,此时赋值函数返回的message2原始对象的临时副本,当它销毁后,用来接收返回值的CMessage对象的Message所指向的指针也随之销毁,输出如下:
Constructor called!
Constructor called!
Destructor Called!
The message is awei is the best!
The message is 葺葺葺葺葺葺葺葺葺葺葺葺
Destructor Called!
此外,当使用(message1 = message2) = message3这样的表达式时,也是不合法的,因为左边表达式的返回结果是message1对象的临时副本,而编译器是不允许利用临时对象来调用成员函数的。
因此,这种情况是必须使用引用来传递参数和返回参数的,而且引用返回值的主要特性是可以作为左值,我们可以在赋值语句左边使用返回引用的函数,如表达式:(message1 = message2) = message3
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:148506次
积分:1754
积分:1754
排名:千里之外
原创:24篇
转载:64篇
(1)(2)(3)(1)(1)(5)(7)(3)(4)(24)(3)(11)(6)(12)(4)(1)其实c语言没有引用这个概念,导致很多语言里的细节其实根本就是矛盾的。光光怪初学者领悟不了,其实有些冤枉。
int get_value_at(int* , int);
int x[20];
*(x + 1) = 2;
get_value_at(x, 1) = 2; /// Compiling error!
x[1]是什么类型?*(x +&1)又是什么类型?
c语言玩弄了一个很geeker的技巧,试图用结果去说明原理:
0)左值可放到等号左边,右值不可以。(这条规则被实际挑战的千疮百孔)
1)x[1]和*(x +&1)是一个左值
2)函数的非void返回值是个右值
3)x+1是一个右值
我们要讲道理,不能用行政命令指挥初学者的大脑:凭什么第一点的那几个操作的结果就这么特殊呢?
第一点确实是一个语言中的特例,这种特例在c语言中其实根本是由于语言的自完备性不足造成的:
1)如果把c语言看作是对汇编的封装,那么&变量&是对&一块连续内存的引用&这个概念的封装。
2)c语言封装了细节之后,又要允许人们去访问其中的细节(打破封装),问题就来了。
既然&变量&是对&一块连续内存的引用&,那我现在想访问这块连续内存中的&某一部分连续内存",这其实就是
*(x +&1) = 2;
这一类操作。问题是这部分内存并没有一个变量来封装它们的引用(数组这块内存有变量封装,可惜数组的元素没有变量去封装),所以c语言又试图拿出左值,右值这些大杀器来说明这些场景。初学者不晕才怪。看我的解释:
3)x[1] = 2;可以看作是 y=2; //这2个操作。但是要注意这个临时定义的变量和我们平时定义的变量略有不同:平时定义的变量包含分配内存这个操作(就是它要去封装的那块内存,&定义即分配&),而我们这里定义的y不分配内存,仅仅用来封装已经分配好的x[1]这块内存的引用。y是左值!
4)struct {int _0; int _1;} x._1 = 2; //这里的x._1和上面的x[1]其实也是一个操作:访问一个连续内存块(这里由数组换成了结构体)的部分内存(由通过下标访问改为了通过成员变量访问)的引用。
5)上面的y是左值还是右值取决于x是左值还是右值。部分服从整体,很好明白吧。
6)c++解除了对引用这个概念的封装,我们终于可以给3)中的y一个合法的语法身份并且完美的解释y的行为了:int &y = x[1]; y = 2; //y不会引起分配内存操作而且y只能固定的引用x[1]。
7)c++明确的把左值和右值划分开了:一个值要么是右值,要么是左值。左值可以取地址,右值不可以。引用类型既然引用的是内存,当然可以取地址,一定是左值,哪怕是做函数的返回值。当然最新的c++ 11草案又扩充了引用的概念,引用也可以是右值,暂且不提。
好了,好事多磨。终于到了本文想说的话了。像x[1],*(x+1)这些特殊的操作有哪些呢,他们有什么特征呢?
返回值是一个引用,是一个左值。
That's it! 我们用事实说话,观察stl中重载运算符的结果,归纳出这些特殊的运算符。
1.前置的++,&--
2.=, +=, -=, *=, /= , &=, |=, ^=, &&=, &&=
4. , (comma, 逗号运算符,在boost的序列初始化等等一组件中可以见到它的重载)
5.不允许重载的运算符: . (dot, 点号运算符,访问结构体成员的 )
实际上-&操作返回的依然是一个右值,一个指针的拷贝。
如果以后你重载运算符,一定要记得这些哦。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:42823次
排名:千里之外
原创:40篇
评论:28条
(1)(2)(1)(1)(2)(1)(1)(3)(5)(13)(9)(1)(1)君,已阅读到文档的结尾了呢~~
运算符的重载 精心收集的各类精品文档,欢迎下载!
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
运算符的重载
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口

我要回帖

更多关于 运算符重载 返回引用 的文章

 

随机推荐