12.5.1 基本运算符重载
我们之前学过的加减乘除等运算,比如两个数相加返回和,本质上是调用一个函数,而函数名称就是加号,只是这个函数的用法有些特殊。
就拿“+”这个函数来说,形参是两个要运算的数,返回值是这两个数的和。
但是系统默认的加号只能运算int,double,string等数据的相加,如果是我们自定义的数据类型,如圆类,怎样相加呢?这就用到运算符重载的技术。
我们先来定义一个圆类,只有一个半径属性:
class Circle
{
public:
Circle() {}
Circle(float r);
public:
int m_R;
};
Circle::Circle(float r)
{
m_R = r;
}
现在我们像实现这样一个功能:
让两个圆类相加,返回一个新的圆类,并且新圆,并且新圆的半径是它们的半径之和。
直接用加号肯定不行,因为加号不支持我们自定义个数据类型来运算。
我们来尝试重载+这个运算符,让它支持两个圆进行相加:
1、通过成员函数进行重载
我们再Circle类中加上这样一个成员函数:
Circle operator+(const Circle &c);
类外给出它的实现:
Circle Circle::operator+(const Circle &c)
{
Circle temp;
temp.m_R = this->m_R + c.m_R;
return temp;
}
观察上面的代码:
- 运算符重载,函数名称是operator加上要重载的运算符;
这样就会发现程序不再报错:
并且正常运行,符合预期设想:
我们来分析以下是怎么实现的:
Circle c3 = c1 + c2;
这行代码中,相当于是c1调用了成员函数operator+(),传入的形参是c2,返回了一个临时的Circle类,并且分析函数代码可以知道返回的Circle类的半径是c1、c2的和。
我们试试按照常规调用成员函数的方法能不能调用:
程序没有报错,事实上,确实可以这样调用。
2、通过全局函数进行重载
除了成员函数,我们还可以用全局函数进行重载,下面写一个用全局函数重载减号的函数:
Circle operator-(const Circle &c1, const Circle &c2)
{
Circle temp;
temp.m_R = c1.m_R - c2.m_R;
return temp;
}
这里可以看到全局函数的重载比成员函数多了一个形参,这是因为成员函数本身会有一个圆类去调用,全局函数不会有圆类去调用。
然后我们去调用它:
int main()
{
Circle c1(10);
Circle c2(20);
Circle c3 = c1 + c2;
c3 = c1.operator+(c2);
Circle c4 = c2 - c1;
c4 = operator-(c2, c1);
cout << c3.m_R << endl;
cout << c4.m_R << endl;
system("pause");
return 0;
}
调用的方式仍然有两种,结果正常:
当然,可以再重载一次加号,实现Circle加上float类型的数据:
Circle Circle::operator+(const float &r)
{
Circle temp;
temp.m_R = this->m_R + r;
return temp;
}
这样时候就能这样写了:
int main()
{
Circle c1(10);
Circle c2(20);
Circle c3 = c1 + c2;
c3 = c1.operator+(c2);
Circle c4 = c2 - c1;
c4 = operator-(c2, c1);
Circle c5 = c1 + 10;
cout << c3.m_R << endl;
cout << c4.m_R << endl;
cout << c5.m_R << endl;
system("pause");
return 0;
}
运行结果符合预期:
但写成这样就不行了,因为这样相当于一个int型去调用加号成员函数,没有符合的定义。
Circle c5 = 10 + c1; //错误