答:1 如果赋值函数返回的是void ,我们知道,其唯一一点需要注意的是,其不支持链式赋值运算,即a=b=c这样是不允许的!
2 对于返回的是类对象本身,还是类对象的引用,其有着本质的区别!
第一:如果其返回的是类对象本身。
A operator =(A& a)
{
if(name!=NULL)
delete name;
this->_id=a._id;
int len=strlen(a.name);
name=new char[len+1];
strcpy(name,a.name);
return *this;
}
其过程是这样的:
class1 A("herengnag");
class1 B;
B=A;
看似简单的赋值操作,其所有的过程如下:
1 释放对象原来的堆资源
2 重新申请堆空间
3 拷贝源的值到对象的堆空间的值
4 创建临时对象(调用临时对象拷贝构造函数),将临时对象返回
5. 临时对象结束,调用临时对象析构函数,释放临时对象堆内存
my god,还真复杂!!
但是,在这些步骤里面,如果第4步,我们没有overload 拷贝函数,也就是没有进行深拷贝。那么在进行第5步释放临时对象的heap 空间时,将释放掉的是和目标对象同一块的heap空间。这样当目标对象B作用域结束调用析构函数时,就会产生错误!!
因此,如果赋值运算符返回的是类对象本身,那么一定要overload 类的拷贝函数(进行深拷贝)!
第二:如果赋值运算符返回的是对象的引用,
A& operator =(A& a)
{
if(name!=NULL)
delete name;
this->_id=a._id;
int len=strlen(a.name);
name=new char[len+1];
strcpy(name,a.name);
return *this;
}
那么其过程如下:
1 释放掉原来对象所占有的堆空间
1.申请一块新的堆内存
2 将源对象的堆内存的值copy给新的堆内存
3 返回源对象的引用
4 结束。
因此,如果赋值运算符返回的是对象引用,那么其不会调用类的拷贝构造函数,这是问题的关键所在!!
复制初始化与赋值的关系
赋值操作,与复制操作不管从过程还是使用方法来看都是那么的想象,所以需要在这里做一个较好的比较和关联。
第一方面:
第二方面:
最后
实例:
#include <iostream>
using namespace std;
class Internet
{
public:
Internet(char *name,char *url)
{
Internet::name = new char[strlen(name)+1];
Internet::url = new char[strlen(url)+1];
if(name)
{
strcpy(Internet::name,name);
}
if(url)
{
strcpy(Internet::url,url);
}
}
Internet(Internet &temp)
{
Internet::name=new char[strlen(temp.name)+1];
Internet::url=new char[strlen(temp.url)+1];
if(name)
{
strcpy(Internet::name,temp.name);
}
if(url)
{
strcpy(Internet::url,temp.url);
}
}
~Internet()
{
delete[] name;
delete[] url;
}
Internet& operator =(Internet &temp)//赋值运算符重载函数
{
delete[] this->name;
delete[] this->url;
this->name = new char[strlen(temp.name)+1];
this->url = new char[strlen(temp.url)+1];
if(this->name)
{
strcpy(this->name,temp.name);
}
if(this->url)
{
strcpy(this->url,temp.url);
}
return *this;
}
public:
char *name;
char *url;
};
int main()
{
Internet a("中国软件开发实验室","www.cndev-lab.com");
Internet b = a;//b对象还不存在,所以调用拷贝构造函数,进行构造处理。
cout<<b.name<<endl<<b.url<<endl;
Internet c("美国在线","www.aol.com");
b = c;//b对象已经存在,所以系统选择赋值运算符重载函数处理。
cout<<b.name<<endl<<b.url<<endl;
system("pause");
}
在类对象还未存在的情况下,赋值过程是通过拷贝构造函数进行构造处理(代码中的Internet b = a;就是这种情况),但当对象已经存在,那么赋值过程就是通过赋值运算符重载函数处理(例子中的b = c;就属于此种情况)。