赋值运算符重载
0.对象赋值时发生了什么
C语言中允许把一个结构体赋值给另外一个相同类型的结构体,C++允许把一个对象赋值给另一个同类的对象。这是通过自动为类重载赋值运算符实现的。这种赋值运算符重载函数原型如下。
Class_name & Class_name::operator=(const Class_name &);
它接受一个指向类对象的常引用,并返回一个指向类对象的引用。c++自动提供的这个函数实现了浅拷贝。接着上篇博文的例子来验证一下。
例1
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
class Man {
char* name;
int age;
public:
Man(char* name, int age);
Man();
Man(const Man & m);
~Man();
void show();
};
Man::Man(char* name, int age)
{
cout<<"call self-def Constructor"<<endl;
this->name = new char[strlen(name) + 1];
strcpy(this->name, name);
this->age = age;
}
Man::Man()
{
cout<<"call default Constructor"<<endl;
this->name = new char[8];
strcpy(this->name, "Unknown");
age = -1;
}
Man::~Man()
{
cout<<"call Destructor"<<endl;
delete[] name;
}
void Man::show()
{
// cout<<"name:"<<name<<endl;
printf("name = %s\n", name);
cout<<"age:"<<age<<endl;
printf("str = %p\n",name);
}
Man::Man(const Man & m)
{
cout<<"call copy Constructor"<<endl;
this->age = m.age;
this->name = new char[strlen(m.name) + 1];
strcpy(this->name, m.name);
}
int main()
{
Man a = Man((char*)"zhengkang", 26);
Man b;
b = a;
a.show();
b.show();
return 0;
}
这个例程的运行结果如下
从运行结果可以看出,a的name指针和b的name指针指向同一片内存区域。执行b = a;跟默认的拷贝构造函数一样,实现的是浅拷贝,那么浅拷贝存在的问题在这里同样存在。释放a的name指向的内存会导致b的name指针指向的内存也被释放掉,这就是需要重载赋值运算符的原因。
1.赋值运算符重载
进行赋值运算符重载实现深拷贝与拷贝构造函数类似,但是也有一些区别。
- 由于目标对象可能引用了以前分配的数据,所以函数应该使用delete[]来释放内存。
- 函数应该避免将对象赋值给自己,否则的话,给对象重新赋值前,释放内存操作可能删除对象的内容。
- 函数需要返回一个指向调用对象的引用。通过返回这样一个引用,可以实现链式操作(即连续赋值),假如a,b,c都是Man对象,那么可以这样写
a=b=c;
等价于a.operator=(b.operator=(c));
下面,我们重载赋值运算符函数。
例2
Man& Man::operator=(const Man& m)
{
cout<<"call = overload func"<<endl;
if (this == &m) //防止a = a这种情况发生
return *this;
delete [] name; //先把原来指向的内存去释放掉
age = m.age;
name = new char[strlen(m.name) + 1];
strcpy(name, m.name);
return *this;
}
重新运行程序,结果如下:
两个对象的name指针指向了不同的内存区域,互不影响。
2.区分两条语句
下面两条语句可能会让人疑惑,需要区分清楚。
Man b;
b = a; //调用复制运算符重载函数进行对象赋值
Man c = a; //调用拷贝构造函数
例3
int main()
{
Man a = Man((char*)"zhengkang", 26); //调用带参数的构造函数
Man b = a; //调用拷贝构造函数
Man c; //调用默认构造函数
c = a; //调用复制运算符重载函数进行对象赋值
return 0;
}
运行结果: