本文topic
为什么重载运算符一定要返回自身引用
结论
正文
重载运算符为什么一定要返回自身的引用的,返回void的不行吗?
返回自身类型不行吗为什么一定要返回自身引用呢?
为了解释清楚这个问题,我们拿赋值运算符举例
首先定义一个简单的Number类
class Number
{
private:
int num;
static int count;//用于计算调用了几次构造函数,包括拷贝构造函数
public:
Number(int n=0):num(n)//默认参数为零,可以同时当默认构造函数使用
{
count++;//每次调用一次加1
cout<<"Count of constructed class Number: "<
对于Numbe这个类,我们一般都是这样来重载赋值运算符的
Number& operator=(const Number& other)
{
num=other.num;
return *this;
}
那么为什么一定要返回自身引用呢?
我们可以将这问题分解为两个问题
我们可以思考一下,如果没有重载赋值运算符,使用普通的函数,我们让一个Number对象等于另外Number对象是这样的
void equal(const Number& other)//写在类里面
{
num=other.num;
}
在main里使用一下
int main()
{
Number n1(1);
Number n2;
n2.equal(n1);
n2.printNumber();
}
而操作符本质上就是函数,那么我们看看能不呢重载一个=的操作符来实现同样的功能
我们来改造一下equal函数
void operator=(const Number& other)//只是改了函数名,将“equal”改为“operator=”
{
num=other.num;
}
调用
int main()
{
Number n1(1);
Number n2;
//n2.equal(n1);
//n2.printNumber();
n2=n1;
n2.printNumber();
}
运行结果
赋值操作符调用成功
那么问题来了,既然void就可以,为什么开头的重载函数要返回Number类型呢?
如果我们回顾一下int类型的赋值我们可以发现它是可以连续赋值的
int main()
{
int i1=2,i2=2,i3=3;
i1=i2=i3; //可以理解为i1=i2,此时i1的值为2,然后i1又等于i3
cout<
运行结果为
此时可以发现(i1=i2)它是有一个返回类型的,返回的类型就是他本身的类型,所以可以实现连续赋值
而我们写的Numer类就不能实现该连续赋值
int main()
{
Number n1(1),n2(2),n3(3);
n1=n2=n3;//如果我们这么写,编译器会报错
}
那么改为返回自身类型呢
Number operator=(const Number& other)
{
num=other.num;
return *this;
}
int main()
{
Number n1(1),n2(2),n3(3);
n1=n2=n3;
n1.printNumber();// 运行结果值为3
}
可以发现一旦改为返回自身类型就可以实现连续赋值了
所以返回自身类型,是为了该操作符能连续使用。
第二问题,为什么要返回Number类型的引用呢?
我们可以同时调用一下文章开头返回Number引用的重载运算符和上面写的不带引用的重载运算符,用同样的代码来测试一下有什么区别。
测试代码均为
int main()
{
Number n1(1),n2(2);
n1=n2;
n1.printNumber();
}
首先是不带引用的运行结果
而这是带引用的运行结果
可以发现带引用的运行结果减少一次拷贝构造和析构。
那么为什么会减少呢?
Number n1(1),n2(2);
n1=n2;
n1.printNumber();
因为上面运行代码中,带引用的话,只新建了n1和n2两个对象,当n1=n2的时候,因为返回的n1的引用,所以返回还是n1这个对象。即(n1=n2)的值,还是n1,只不过n1里面的变量值变了。
而不带引用时,在赋值重载函数中,return *this的时候,用n1拷贝构造了一个临时对象,然后因为没有左值接受这个临时变量,所以又被析构了。即(n1=n2)的值是一个临时变量,刚新建,就被析构了。所以多了一个拷贝构造函数和析构函数,因此返回引用类型会带来了一点性能的提升。