运算符重载——类内重载
实验目的
学习并掌握C++运算符重载相关的内容
实验内容
运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
在C++中,我们可以重载大部分内置的运算符
运算符。
重载有两种方式,一种是类内重载(运算符重载为类的成员函数),一种是类外重载(运算符重载为类的友元函数)。
这里我们先介绍类内重载
最简单的函数重载
在进行运算符重载前,我们先来一个最简单的函数重载。
类内重载
普通运算符:±*/
下面为源代码
#include <iostream>
using namespace std;
class num
{
public:
num operator+(num& y)
{
num temp;
temp.lenth=this->lenth+y.lenth;
temp.width=this->width+y.width;
return temp;
}
num operator-(num& y)
{
num temp;
temp.lenth=this->lenth-y.lenth;
temp.width=this->width-y.width;
return temp;
}
num operator*(num& y)
{
num temp;
temp.lenth=this->lenth*y.lenth;
temp.width=this->width*y.width;
return temp;
}
num operator/(num& y)
{
num temp;
temp.lenth=this->lenth/y.lenth;
temp.width=this->width/y.width;
return temp;
}
int lenth;
int width;
};
int main()
{
num x,y;
x.lenth=31;
x.width=4;
y.lenth=62;
y.width=8;
num z=x+y;
cout<<"重载后,两者相加"<<endl;
cout<<z.lenth<<endl;
cout<<z.width<<endl;
z=x-y;
cout<<endl;
cout<<"重载后,两者相减"<<endl;
cout<<z.lenth<<endl;
cout<<z.width<<endl;
z=x*y;
cout<<endl;
cout<<"重载后,两者相乘"<<endl;
cout<<z.lenth<<endl;
cout<<z.width<<endl;
z=x/y;
cout<<endl;
cout<<"重载后,两者相除"<<endl;
cout<<z.lenth<<endl;
cout<<z.width<<endl;
}
运行结果
先看类num的定义,我们定义每个num对象都有两个int类型的属性,lenth和width;然后重载运算符:+、-、*、/。
对于operator+:直接把两个num对象的两个属性分别相加,得到新的num对象,其中x.length=31,y.lenth=62,相加得到z.lenth=93;
对于operator-:直接把两个num对象的两个属性分别相减,得到新的num对象,其中x.length=31,y.lenth=62,相减得到z.lenth=-31;
对于operator*:直接把两个num对象的两个属性分别相乘,得到新的num对象,其中x.length=31,y.lenth=62,相乘得到z.lenth=1922;
对于operator/:直接把两个num对象的两个属性分别相除,得到新的num对象,其中x.length=31,y.lenth=62,相除取整得到z.lenth=0;
疑问:为什么重载运算符的形参要用引用?一定要用引用吗?
在代码中,要注意的是,重载运算符时,形式参数使用了引用。其实引用不是必须要用的,但使用引用可以大大减少对象拷贝的开销;在我的理解中,重载运算符时一般不会改变形参的值,所以为了减少构造开销可以使用引用,这是很常见的一个技巧,而且,若是担心实参因此被改变,也可以在形参前添加const关键字,如下:
num operator+(const num& y){}
”=”运算符重载
源代码修改添加如下:
num& operator=(const num& y)
{
cout<<"使用了重载后的=运算符"<<endl;
this->width=y.width;
this->lenth=y.lenth;
return *this;
}
int lenth;
int width;
};
int main()
{
num x,y;
x.lenth=31;
x.width=4;
y.lenth=62;
y.width=8;
num z;
z=x=y;
cout<<"重载=运算符后的x"<<endl;
cout<<x.lenth<<endl;
cout<<x.width<<endl;
cout<<endl;
cout<<"重载=运算符后的y"<<endl;
cout<<y.lenth<<endl;
cout<<y.width<<endl;
cout<<endl;
cout<<"重载=运算符后的z"<<endl;
cout<<z.lenth<<endl;
cout<<z.width<<endl;
}
相对上次的代码,只更新了函数
num& operator=(const num& y)和main函数。
结果如下:
我们发现,它调用了两次我们重载后的”=”运算符,而且这个计算结果是x和y、z相等,都等于之前y的值,这说明实现计算x=y,再计算z=x;
然后我们若是更改代码,将
num z;
z=x=y;
更改为
num z=x;
cout<<"------------------------"<<endl;
x=y;
结果变为
这说明在构造新对象时用=运算符,它还是会调用原来的而不是我们重载后的=运算符。
问题 为什么重载=运算符,它的返回类型需要使用引用?
因为这样可以减少拷贝构造的时间耗费,此外就是这样可以实现连续赋值。
我们再次来改变代码,得到
num z;
(z=x)=y;
在使用引用的情况下,结果如下:
这个结果说明,先计算z=x,再计算z=y,实现了连续赋值;
但返回值若不使用引用,结果如下
这说明在计算完z=x后就没有成功的再次将y的值赋给z。
因为如果返回的类型是值,不是引用,那么在计算z=x时,执行重载的=运算符,返回的是一个匿名对象,它是一个右值,这个临时右值不能成功执行=z,因为右值不能当左值使用,而引用既可以作右值,也可以作左值。
实验结论
运算符重载可以帮助我们让运算符之前不能完成的任务完成,但是重载一定要考虑清楚使用情况和条件,避免出现错误,而且,非必要重载!