本章内容均为coursera中C++程序设计第三周课件的整理
赋值运算符 ‘=’ 的重载
赋值运算符两边的类型可以不匹配:
• 把一个 int类型变量赋值给一个 Complex对象
• 把一个 char * 类型的字符串赋值给一个字符串对象
赋值运算符 “=” 只能重载为成员函数
举例:编写一个长度可变的字符串类String
• 包含一个char * 类型的成员变量指向动态分配的存储空间,该存储空间用于存放 ‘\0’ 结尾的字符串
class String {
private:
char * str;
public:
String () : str(NULL) { } //构造函数, 初始化str为NULL
const char * c_str() { return str; }
char * operator = (const char * s);
~String( );
};
//重载 ‘=’ 使得obj = “hello”能够成立
char * String::operator = (const char * s){
if(str) delete [] str;
if(s) { //s不为NULL才会执行拷贝
str = new char[strlen(s)+1];
strcpy(str, s);
}
else
str = NULL;
return str;
}
String::~String( ) {
if(str) delete [] str;
};
int main(){
String s;
s = “Good Luck,” ; //s.operator=(xxx)
cout << s.c_str() << endl;
// String s2 = “hello!”; //这条语句要是不注释掉就会出错,
//这并不是赋值语句,而是一个初始化语句,并不会调用赋值
//它需要调用构造函数String(char*)
s = "Shenzhou 8!";
cout << s.c_str() << endl;
return 0;
}
程序输出结果:Good Luck,
Shenzhou 8
重载赋值运算符的意义 – 浅复制和深复制
S1 = S2;
浅复制/浅拷贝
• 执行逐个字节的复制工作
MyString S1, S2;
S1 = “this”;
S2 = “that”;
S1 = S2;
如图所示,浅拷贝会导致的问题:
1、S1原本的内存变成了垃圾内存;
2、s1和s2同时指向了“that”,当s1和s2消亡的时候,
此空间会被释放两次,这样会导致严重的内存错误。
重载赋值运算符的意义 – 浅复制和深复制
深复制/深拷贝
• 将一个对象中指针变量指向的内容,复制到另一个对象中指针成员对象指向的地方
MyString S1, S2;
S1 = “this”;
S2 = “that”;
S1 = S2;
在 class MyString 里添加成员函数:
String & operator = (const String & s) {
if(str) delete [] str;
str = new char[strlen(s.str)+1];
strcpy(str, s.str);
return * this;
}
思考面语句,是否会有问题?
MyString s;
s = “Hello”;
s = s;
正确写法:
String & String::operator = (const String & s){
if(str == s.str) return * this;
if(str) delete [] str;
if(s.str) { //s.str不为NULL才会执行拷贝
str = new char[strlen(s.str)+1];
strcpy( str,s.str);
}
else
str = NULL;
return * this;
}
void 好不好?不可以。
考虑: a = b = c;
//等价于a.operator=(b.operator=(c));
String 好不好?
operator = 返回值类型用String &
运算符重载时, 好的风格 -- 尽量保留运算符原本的特性
考虑: (a=b)=c; //会修改a的值
分别等价于:
(a.operator=(b)).operator=(c);
为 String类编写复制构造函数时会面临和 ‘=’ 同样的问题(浅拷贝与深拷贝), 用同样的方法处理
String::String(String & s)
{
if(s.str) {
str = new char[strlen(s.str)+1];
strcpy(str, s.str);
}
else
str = NULL;
}