赋值运算符重载引发的思考(引用的功能) http://blog.csdn.net/yorkcai/article/details/8567441

来源:互联网 发布:测量软件手机版 编辑:程序博客网 时间:2024/05/16 15:53
引用网址:http://blog.163.com/zjf_to/blog/static/20142906120121723236624/
[cpp] view plaincopy
  1. #include <iostream>  
  2. #include "string.h"  
  3. using namespace std;  
  4.   
  5. class CMessage {  
  6. private:  
  7.     char* Message;  
  8. public:  
  9.     CMessage(char* MessageText = "Default Text!") {  
  10.         cout<<"Constructor called!"<<endl;  
  11.         Message = new char[strlen(MessageText) + 1];  
  12.         strcpy(Message, MessageText);  
  13.     }  
  14.     void ShowMessage() {  
  15.         cout<<"The message is "<<Message<<endl;  
  16.     }  
  17.     ~CMessage() {  
  18.         cout<<"Destructor Called!"<<endl;  
  19.         cout << "Delete data" <<endl;  
  20.         delete[] Message;  
  21.     }  
  22.       
  23.     CMessage& operator =(const CMessage& OtherObject) {  
  24.         cout << "override assignment operator function" <<endl;  
  25.         if (this != &OtherObject)//检查对象是否已经赋值给自身  
  26.         {  
  27.             delete [] Message;   
  28.             Message = new char[strlen(OtherObject.Message) + 1];  
  29.             strcpy(Message, OtherObject.Message);  
  30.         }  
  31.         return *this;  
  32.     }  
  33. };  
  34.   
  35. int main(int argc, char* argv[]) {  
  36.     CMessage message1("awei is the best!");  
  37.     CMessage message2;  
  38.     CMessage message3("abcdefadfadf");  
  39.     message2 = message1;  
  40.     message1.ShowMessage();  
  41.     message2.ShowMessage();  
  42.     /* 
  43.     (message1=message2)=message3; 
  44.     message1.ShowMessage(); 
  45.     message2.ShowMessage(); 
  46.     message3.ShowMessage(); 
  47.     */return 0;  
  48. }  


如果我们不重载赋值运算符,那么类会自动为我们提供一个赋值运算符,这个默认的赋值运算符函数跟默认的复制构造函数是一样的,就是把一个对象的数据成员的值复制给另一个对象对应的数据成员,在做此测试时,我也遇到了一个问题,直接利用默认赋值函数,引发内存溢出的问题,

代码及原因解释如下:

//////////////////////////////////////////////////////////////////////////
 //如果不重载赋值运算符,则下面这条语句
 /
/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

0 0