为什么要对赋值运算符“=”进行重载
- 某些情况下,当我们编写一个类的时候,并不需要为该类重载“=”运算符,因为编译系统为每个类提供了默认的赋值运算符“=”,使用这个默认的赋值运算符操作类对象时,该运算符会把这个类的所有数据成员都进行一次赋值操作。
- 当程序没有显式地提供一个以本类或本类的引用为参数的赋值运算符重载函数时,编译器会自动生成这样一个默认的赋值运算符重载函数。
- 例如有如下类:
boy.h
#pragma once
#include <string>
using namespace std;
class Boy{
public:
Boy(const char* name = "无名", int age = 0, int salary = 0);
~Boy();
//定义了赋值运算符重载
Boy& operator=(const Boy& boy);
string description() const;
private:
char* name; //姓名
int age; //年龄
int salary; //薪资
};
boy.cpp
#include <iostream>
#include <sstream>
#include "Boy.h"
Boy::Boy(const char* name, int age, int salary){
if (!name) {
name = (char*)"未命名";
}
this->name = new char[strlen(name)+1];
strcpy_s(this->name, strlen(name)+1, name);
this->age = age;
this->salary = salary;
}
Boy::~Boy(){
if (name) {
delete name;
name = NULL;
}
}
Boy& Boy::operator=(const Boy& boy){
if (name) { //如果当前对象的name不为空
delete name; //释放内存
name = NULL; //指向空
}
//重新分配一块 boy.name 大小的内存
this->name = new char[strlen(boy.name) + 1];
strcpy_s(this->name, strlen(boy.name) + 1, boy.name);
this->age = boy.age;
this->salary = boy.salary;
return *this; //返回当前对象的引用
}
string Boy::description() const{
stringstream ret;
ret << "姓名:" << name << "\t年龄:" << age << "\t薪资:" << salary;
return ret.str();
}
main.cpp
#include <iostream>
#include <Windows.h>
#include "Boy.h"
using namespace std;
int main(void) {
Boy boy1("张三", 18, 10000);
Boy boy2;
Boy boy3;
//调用赋值运算符 Boy& operator=(const Boy& boy);
boy3 = boy2 = boy1;
cout << boy1.description() << endl;
cout << boy2.description() << endl;
cout << boy3.description() << endl;
system("pause");
return 0;
}
总结:
-
一般地,赋值运算符重载函数的参数是函数所在类的const类型的引用
-
加const是因为:
①我们不希望在这个函数中对用来进行赋值的“原版”做任何修改。
②加上const,对于const的和非const的实参,函数就能接受;如果不加,就只能接受非const的实参。
-
用引用是因为:
这样可以避免在函数调用时对实参的一次拷贝,提高了效率。
-
注意:
上面的规定都不是强制的,可以不加const,也可以没有引用,甚至参数可以不是函数所在的对象。
返回值是被赋值者的引用,即*this,
-
原因是
①这样在函数返回时避免一次拷贝,提高了效率。
②更重要的,这样可以实现连续赋值,即类似a=b=c这样。如果不是返回引用而是返回值类型,那么,执行a=b时,调用赋值运算符重载函数,在函数返回时,由于返回的是值类型,所以要对return后边的“东西”进行一次拷贝,得到一个未命名的副本(有些资料上称之为“匿名对象”),然后将这个副本返回,而这个副本是右值,所以,执行a=b后,得到的是一个右值,再执行=c就会出错。
-
注意:
这也不是强制的,我们可以将函数返回值声明为void,然后什么也不返回,只不过这样就不能够连续赋值了。