赋值运算符'='的重载
- 有时会希望赋值运算符两边的类型不匹配,比如把一个
int
类型变量赋值给一个complex
对象,或者把一个char*
类型的字符串赋值给一个字符串对象 - 注意:赋值运算符
=
只能重载为成员函数
class String{
private:
char*str;
public:
String():str(new char[1]){str[0]=0;}
const char* c_str(){return str;}
String & operator = (const char*s);
String::~String(){delete[] str;}
};
String & String::operator = (const char*s)
{ //重载使得obj="hello"能够成立
delete[]str;
str=new char[strlen(s)+1;
strcpy(str,s);
return *this;
}
int main()
{
String s;
s="Good Luck,";//等价于s.operator=("Good Luck,");
cout<<s.c_str()<<endl;
//String s2="hello";//如果这条语句不注释掉,编译会出错,这是初始化语句,调用的是构造函数
s="shenzhou";//等价于s.operator=("shenzhou")
cout<<s.c_str()<<endl;
return 0;
}
- 输出
Good Luck,
shenzhou
浅拷贝和深拷贝
- 问题
上述代码似乎没有什么问题,但是如果遇到了
String s1,s2;
s1="this";
s2="that";
s1=s2;
是有问题的
- 这样的操作输出结果是对的,但是内部的动作却是把s1的str指向了s2的str指向的地方,对于后来的操作是大大不利的
- 还有一点,如果s1对象消亡,则析构函数将释放s1.str指向的地方,则等价于释放了s2.str的指向地方,后面s2消亡时又会再释放一次s2.str的指向,不妥
- 另外,如果执行s1="other",会导致s2.str指向的地方被delete
- 解决
- 在class String里添加成员函数
String & operator = (const String & s){
delete[]str;
str=new char[strlen(s.str)+1];
strcpy(str,s.str);
return *this;
}
看似没有问题了,实际上还有问题
- 问题
- 对于
String s;
s="hello";
s=s;
会有问题,一上来就被delete掉了
- 改进
String & operator = (const String &s){
if(this==&s)
return *this;
delete[]str;
str=new char[strlen(s.str)+1];
strcpy(str,s.str);
return *this;
}
- 至此,问题基本解决
对operator=的返回值类型的讨论
- 为什么不用void,String?
- 因为对运算符重载的时候,好的风格是应该尽量保留运算符原本的特性
- 如:
a=b=c;//void不行,先进行b=c返回void,那么a=void
(a=b)=c;//string不行,a=b返回一个String,变成String=c