c语言中允许把一个结构体赋值给另外一个相同类型的结构体,c 允许把一个对象赋值给另一个同类的对象。这是通过自动为类重载赋值运算符实现的。这种赋值运算符重载函数原型如下。
class_name & class_name::operator=(const class_name &);
它接受一个指向类对象的常引用,并返回一个指向类对象的引用。c 自动提供的这个函数实现了浅拷贝。接着上篇博文的例子来验证一下。
例1
#include
#include
#include
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"<name = new char[strlen(name) 1];
strcpy(this->name, name);
this->age = age;
}
man::man()
{
cout<<"call default constructor"<name = new char[8];
strcpy(this->name, "unknown");
age = -1;
}
man::~man()
{
cout<<"call destructor"<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指针指向的内存也被释放掉,这就是需要重载赋值运算符的原因。
进行赋值运算符重载实现深拷贝与拷贝构造函数类似,但是也有一些区别。
- 由于目标对象可能引用了以前分配的数据,所以函数应该使用delete[]来释放内存。
- 函数应该避免将对象赋值给自己,否则的话,给对象重新赋值前,释放内存操作可能删除对象的内容。
- 函数需要返回一个指向调用对象的引用。通过返回这样一个引用,可以实现链式操作(即连续赋值),假如a,b,c都是man对象,那么可以这样写
a=b=c;
等价于a.operator=(b.operator=(c));
下面,我们重载赋值运算符函数。
例2
man& man::operator=(const man& m)
{
cout<<"call = overload func"<
重新运行程序,结果如下:
两个对象的name指针指向了不同的内存区域,互不影响。
下面两条语句可能会让人疑惑,需要区分清楚。
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;
}
运行结果: