一、运算符重载
1、重载对象的赋值运算符
编译器在默认情况下为每个类生成一个默认的赋值操作,用于同类的两个对象之间赋值。默认的含义是逐个为成员赋值,即将一个对象成员的值赋给另一个对象相应的成员,这种赋值方式对于有些类可能是不正确的。假设类Str的数据成员char *st,则下面的语句经赋值后是有问题的:
Str s1("hello"),s2("world");
s2 = s1;
经赋值后,s2.st和s1.st是同一块存储地址,当它们的生存周期结束时,存储“hello”的变量被删除了两次,这是个严重的错误。另外,对于s1 = s1的情况,也应不执行赋值操作。因此,程序必须为Str类定义自己的赋值操作符“=”,可使用如下的方法实现:
Str& Str::operator=(Str &s){
if(this == &s){//防止s=s这样的赋值
return *this;
}
delete st;
st = new char[strlen(s.st)+1];//申请内存
strcpy(st,s.st);//将对象s的数据复制一份到申请的内存区
return *this;//返回this指针指向的对象
}
上面这个方法必须使用引用参数,关键字operator和=一起表示一个运算符函数,这里可以将operator=整体上视为一个函数名,这样的话就可以把它声明为:
Str& operator= (Str &);
即函数operator=(Str &)返回Str类对象的引用,它在定义时可以写成如下形式:
Str& Str::operator=(Str &s){
//函数体
}
调用函数时写成如下形式:
Str s1,s2;
s2.operator=(s1);
但由于要实现的是=的作用,所以这里可以简写为如下形式:
Str s1,s2;
s2=s1
下面是一个完整的示例:
class Str{
private:
char *st;
public:
Str(char *);//使用字符指针的构造函数
Str(Str &);//使用对象引用的构造函数
Str& operator=(char *);//重载使用字符指针的赋值运算符
Str& operator=(Str &);//重载使用对象引用的赋值运算符
void print(){
cout << st << endl;
}
~Str(){
delete st;
}
};
Str::Str(char *c){
st = new char[strlen(c)+1];//字符数组以\0结尾,需要多申请一个字符长度的内存空间
strcpy(st,c);//将字符串复制到内存区st
}
Str::Str(Str &s){
st = new char[strlen(s.st)+1];//申请内存
strcpy(st,s.st);//将对象s的字符串复制到申请的内存区
}
Str& Str::operator=(char *c){
delete st;//先释放内存空间
st = new char[strlen(c)+1];//重新申请内存
strcpy(st,c);//将字符串c复制到内存区
return *this;
}
Str& Str::operator=(Str &s){
if(this == &s){//防止s=s这样的赋值
return *this;
}
delete st;//先释放内存
st = new char[strlen(s.st)+1];//重新申请内存
strcpy(st,s.st);//将对象s的字符串复制到新申请的内存区
return *this;//返回this指针指向的对象
}
#include <string>
#include <string.h>
#include "Example1.h"
void example1();
int main() {
example1();
return 0;
}
void example1() {
Str s1("hello"), s2("world"), s3(s1);
s1.print();
s2.print();
s3.print();
// hello
// world
// hello
s2 = s1 = s3;
s3 = "other";
s1.print();
s2.print();
s3.print();
// hello
// hello
// other
}
2、运算符重载的实质