10.2 运算符重载的方法
运算符重载的方法是定义一个重载运算符的函数,使指定的运算符不仅能实现原有的功能,而且能实现在函数中指定的新功能。运算符重载实际上是函数的重载。
重载运算符的函数一般格式如下:
函数类型 operator 运算符名称 ( 形参表 )
{
对运算符的重载处理;
}
例子中实现了一个简单的复数相加。
#include <iostream>
using namespace std;
class Complex
{
private:
double real;
double imag;
public:
Complex( double rr = 0, double ii = 0 ):real(rr), imag(ii){}
Complex operator +( Complex & r )
{
Complex tmp;
tmp.real = real + r.real;
tmp.imag = imag + r.imag;
return tmp;
}
void display()
{
cout << real << '+' << imag << 'i' << endl;
}
};
int main()
{
Complex c1(1,1);
Complex c2(2,2);
Complex c3;
c3 = c1 + c2;
c3.display();
return 0;
}
说明:
1)c++编译系统把程序中的表达式c1+c2解释为c1.operaor+(c2)
2)同一运算符可以代表不同的功能,编译系统是根据运算符两侧(如果是单目运算符则为一侧)的数据类型决定的。
10.3运算符重载的规则
1)只能对已有的c++运算符进行重载。
2)c++中绝大部分的运算符可以重载。
不能重载的运算符只有5个:
. (成员访问运算符)
* (成员指针访问运算符)
::(域运算符)
sizeof(长度运算符)
?: (条件运算符)
3)重载不能改变运算符运算对象(即操作数)的个数
4)重载不能改变运算符的优先级别
5)重载不能改变运算符的结合性
6)重载运算符的函数不能有默认的参数
7)重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个是类对象(或类对象的引用)
8)用于类对象的运算符一般必须重载,但有两个例外,运算符“=”和“&”不必用户重载:
(i) 系统已为每一个新声明的类重载了一个赋值运算符,它的作用是逐个复制类的数据成员。
(ii)地址运算符&也不必重载,它能返回类对象在内存中的起始地址。
9)可以将一个运算符重载为执行任意的操作,应当使重载运算符的功能类似于该运算符作用于标准类型数据时所实现的功能。
10.4 运算符重载函数作为类成员函数和友元函数
对运算符重载的函数有两种处理方式:
(1) 把运算符重载的函数作为类的成员函数
此时有一个参数是隐含的,运算符函数是通过this指针隐式地访问类对象的成员。
(2) 运算符重载的函数不是类的成员函数(可以是一个普通函数),在类中把它声明为友元函数(友元函数的目的是方便访问私有成员)。
如下例:
#include <iostream>
using namespace std;
class Complex
{
private:
double real;
double imag;
public:
Complex( double rr = 0, double ii = 0 ):real(rr), imag(ii){}
friend Complex operator +( Complex & r1, Complex & r2 )
{
Complex tmp;
tmp.real = r1.real + r2.real;
tmp.imag = r1.imag + r2.imag;
return tmp;
}
void display()
{
cout << real << '+' << imag << 'i' << endl;
}
};
int main()
{
Complex c1(1,1);
Complex c2(2,2);
Complex c3;
c3 = c1 + c2;
c3.display();
return 0;
}
那什么时候将运算符重载函数作为成员函数,什么时候用友元函数方式?
1)如果将运算符重载函数作为成员函数。它可以通过this指针自由地访问本类数据成员,因此可以少写一个函数的参数。但必须要求运算表达式第一个参数(即运算符左侧的操作数)是一个类对象,而且与运算符函数的类型相同。
2) 将双目运算符的表达式重载为友元函数时,由于友元函数不是该类的成员函数,因此在函数的形参表列中必须有两个参数,不能省略。在使用运算符的表达式中,要求运算符左侧的操作数与函数第一个参数对应,运算符右侧的操作数与函数的第二个参数对应。