赋值运算符的重载,应该使用这种方式:
Boy& operator=(const Boy &boy);
注意:参数要使用引用!
正确的完整代码为:
Boy类(所在文件:“Boy.h”):
#include <string>
using namespace std;
class Boy{
public:
Boy(const char *name = NULL);
~Boy();
Boy& operator=(const Boy& boy);
string getName();
private:
char *name;
};
Boy类的实现(所在文件:Boy.cpp):
#include "Boy.h"
Boy::Boy(const char *name) {
//判断传递的是否为空指针,是空指针就是没有命名
if(!name) {
name = "未命名";
}
this->name = new char[strlen(name) + 1];
strcpy_s(this->name, strlen(name) + 1, name);
}
Boy& Boy::operator=(const Boy& boy) {
if(name) delete name;
this->name = new char[strlen(boy.name) + 1];
strcpy_s(this->name, strlen(name) + 1, boy.name);
return *this;
}
string Boy::getName() {
return name;
}
Boy::~Boy() {
if(name) delete[] name;
}
主函数入口点:
#include <iostream>
#include "Boy.h"
int main(void) {
Boy boy1("大鱼");
Boy boy2, boy3;
boy3 = boy2 = boy1;
cout << boy1.getName() << endl;
cout << boy2.getName() << endl;
cout << boy3.getName() << endl;
return 0;
}
正确编译结果:
错误一:
如果定义成:
Boy& operator=(const Boy *boy);
这样定义,该函数不起作用,编译器不会识别为赋值运算符的重载,也就是:boy2 = boy1时不会调用这个函数。
这时调用的是编译器自动生成的赋值构造函数,但程序结束时会崩掉!
原因是,编译器自动生成的赋值构造函数是进行浅拷贝的,将指针name的值拷贝了,没有重新给name分配空间,导致三个对象中的数据name都使用同一个空间,析构函数调用了三次,同一个数据name被释放了三次,程序崩掉!!!
错误二:
如果定义:
Boy& operator=(const Boy boy);
有效果,但是在调用时,会执行参数的传递:
就是说,执行boy2 = boy1;时,就会执行: boy2.operator=(boy);
然而,执行 boy2.operator=(boy);时,就会执行: const Boy boy = boy1;
执行 const Boy boy = boy1;,就会执行Boy类的拷贝构造函数!
但是,并没有定义拷贝构造函数。那么,编译器会自动生成拷贝构造函数,进行浅拷贝!
浅拷贝就是直接把boy1.name这个指针变量的值直接拷贝到指针boy.name,导致这两个指针指向同一个地址,这就很危险!由于boy这个变量是临时变量,在这个函数执行完之后,就会消亡!消亡就会调用析构函数释放掉内存,这时,boy1.name与boy.name指向的值就是随机的,乱七八糟的数据,如下:
这样定义赋值构造函数:Boy& operator=(const Boy boy),有两个影响:
1)浪费性能
2)如果没有自定义的拷贝构造函数,而且这个类又有指针成员时,就会调用自动生成的拷贝构造函数,导致浅拷贝
如果析构函数中,对这个指针指向的内存做了释放,那就导致数据损坏或程序崩溃!
小结:
1)赋值运算符的重载,一定要使用引用参数
2)如果一个类有指针成员,而且使用了动态内存分配,那么一定要定义自己的拷贝构造函数【要使用深拷贝】,避免调用自动生成的拷贝构造函数
因为自动生成的拷贝构造函数,是浅拷贝!