第四周 运算符重载
1.运算符重载的基本概念
2.赋值运算符的重载
3.运算符重载为友元函数
4.运算符重载实例:可变长数组类的实现
5.流插入运算符和流提取运算符的重载
6.类型转换运算符、自增自减运算符的重载
2.赋值运算符的重载
有时候希望赋值运算符两边的类型可以不匹配,比如,把一个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 8!"; //于 等价于 s.operator=("Shenzhou 8!");
cout << s.c_str() << endl;
return 0;
}
输出:
Good Luck,
Shenzhou 8!
浅拷贝和深拷贝
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){
delete [] str;
str = new char[strlen(s)+1];
strcpy( str, s);
return * this;
};
~String( ) { delete [] str; }
};
String S1, S2;
S1 = “this”;
S2 = “that”;
S1 = S2;
如果不定义自己的赋值运算符:
结果是那么S1=S2实际上导致 S1.str和 S2.str指向同一地方。
这会产生以下几个后果
1) S1.str原来指向的地方被废弃,永远不会再被释放,成为内存垃圾;
2) 如果S1对象消亡,析构函数将释放 S1.str指向的空间,则S2消亡时还要释放一次,不妥,因为new出来的空间只能delete一次,程序崩溃。
3) 另外,如果执行 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;//用自己赋值自己
问题:自己的内存已经先被释放了,然后访问就回出错
解决办法:
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 好不好?
为什么是 String &
对运算符进行重载的时候,好的风格是应该尽量保留运算符原本的特性
考虑: a = b = c;和 (a=b)=c; //会修改a的值
分别等价于:
a.operator=(b.operator=(c));
(a.operator=(b)).operator=(c);//(a=b)返回a的引用
上面的String类是否就没有问题了?
为 String类编写复制构造函数的时候,会面临和 = 同样的问题,用同样的方法处理。避免指向同一个空间
String( String & s)
{
str = new char[strlen(s.str)+1];
strcpy(str,s.str);
}