赋值运算符可能是最容易令人迷惑的一个,所以,重载它必须十分的小心。
1. 值运算符仅能重载为成员函数。
C++不允许赋值运算符被重载为全局形式,这是因为如果可以写出全局形式的赋值运算符函数的话,我们可以写出这样的函数:
iint operator=(int a, integer b);
从而出现这样无法无天的语句:
integer a(3);
2 = a;//God save me
2. 注意自赋值的情况
现在我们写一个简单的integer类并重载赋值运算符。
class integer
{
int i;
public:
integer(int j):i(j){};
integer& operator=(const integer& a)
{
i = a.i;
return *this;
};
};
嗯,不错。但,且慢,你没有考虑自赋值的情况。啊,有必要吗?的确,在这个例子中找不到检测自赋值的理由,但请看下面这个例子:
class CA
{
public:
char* p;
CA(){p = NULL;};
void Set(char* pStr)
{
delete []p;
if(pStr == NULL)
{
p = NULL;
}
else
{
p = new char[strlen(pStr)+1];
strcpy(p, pStr);
}
};
CA& operator=(CA& a)
{
cout<<” operator = invoked\\n”<<endl;
//没有检测自赋值情况
delete []p;
p = a.p;
a.p = NULL;
return *this;
};
~CA(){delete []p;};
};
CA对象“拥有”它成员p指向的内存。所以,在赋值函数中,参数a将放弃 它的“拥有权”,并将它转交给调用对象。(C++标志库中定义的智能指针auto_ptr就是一种“拥有”型智能指针,它也存在这种“拥有权转移”的性质)
请见下面的例子代码(例子代码1):
CA a1, a2;
a1.Set(“Ok”);
a2 = a1;
我们的函数看起来工作的很好,但是,请看下面一条语句:
a2 = a2;// 悲剧发生了,a2“拥有”的内存被释放了!
所以,赋值运算符函数应写为下面的形式:
CA& CA::operator=(CA& a)
{
cout<<” operator = invoked\\n”<<endl;
//检测自赋值情况
if(this != &a)
{
delete []p;
p = a.p;
a.p = NULL;
}
return *this;
};
正因为在自赋值的情况下可能给对象造成伤害,所以在重载赋值运算符时必须要注意自赋值的情况。所谓习惯成自然,如果我们养成良好的习惯,我们就会避免犯种种错误。
所以integer类中的赋值运算符函数应写成这样:
integer& integer::operator=(const integer& a)
{
if(this != &a)