一、定义
对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
二、举例
1、重载+运算符来实现复数类对象的之间的加法
class CComplex
{
public:
CComplex (int r=10,int i=10):mreal(r),mimage(i)
{}
~CComplex(){}
CComplex (const CComplex &src):mreal(src.mreal),mimage(src.mimage)//拷贝构造函数
{}
CComplex & operator=(const CComplex&src)//赋值函数
{
mreal=src.mreal;
mimage=src.mimage;
return *this;
}
CComplex operator + (const CComplex &src)//重载
{
return CComplex (mreal+src.mreal , mimage+src.mimage);
}
private:
int mreal;
int mimage;
friend ostream & operator<<(ostream &out,const CComplex &src);
friend istream &operator>>(istream &in, CComplex &src);
friend CComplex operator+(const CComplex &lhs,const CComplex &rhs);
}
2、重载+=运算符
void operator += (const CComplex &src)//重载+=
{
mreal+=src.mreal ;
mimage+=src.mimage ;
}
3、重载前置++运算符
CComplex & operator++()//前置加一
{
mreal++;
mimage ++;
return *this;//this不是局部就返回引用,局部不能返回引用
}
4、重载后置++运算符
CComplex operator++(int)//后置加一
{
return CComplex (mreal++,mimage ++);//先构造临时对象,再加一
}
5、重载流插入(<<)运算符
此时要在类体中将该函数声明为友元函数
ostream &operator<<(ostream &out,const CComplex &src)//返回引用不会再产生临时对象
{
out<<"real:"<<src.mreal<<" "<<"image:"<<src.mimage;
return out;
}
6、重载流提取(>>)运算符
同样要在类体中将该函数声明为友元函数
istream &operator>>(istream &in,CComplex &src)
{
in>>src.mreal>>src.mimage ;
return in;
}
- 对于用户自己定义的类型的数据(如类对象),是不能直接用“<<”和“>>”来输出和输入的。如果用户用他们输出和输入自己生命的类型的数据必须对他们进行重载。
- 重载运算符“>>”的函数的第一个参数和函数的类型都必须是“istream &”类型(即istream类对象的引用),第二个参数是要进行输入操作的类。
- 因此只能将重载“>>”和“<<”的函数作为友元函数,而不是将他们定义为成员函数。
- 如何区分什么情况下“<<”是标准类型数据的流插入符,什么情况下的“<<”是重载的流插入符??
~~cout<<c3~~ <<5<<endl;
带~~的前一部分是调用重载的流插入运算符,后面两个“<<”不是重载的流插入符,因为它的右侧不是Complex类对象而是标准类型的数据,是用预定义的流插入符出处理的。
7、重载+运算符
在类体中将该函数声明为友元函数
CComplex operator+(const CComplex &lhs,const CComplex &rhs)
{
return CComplex (lhs.mreal +rhs.mreal ,lhs.mimage +rhs.mimage );
}
三、重载运算符的规则
-
C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载。
-
不重载的运算符有5个(. 成员访问运算符 *成员指针访问运算符 ::域运算符 sizeof长度运算符 ?:条件运算符)
-
重载不能改变运算对象(操作数)的个数
-
重载不能改变运算符的优先级
-
重载不能改变运算符的结合性
-
重载运算符的函数不能有默认的参数
-
重载的运算符必须和用户的自定义类型的对象一起使用,其参数至少有一个是类对象(或类对象的引用)。也就是说,参数不能全是C++标准类型,以防止用户修改用于标准类型数据的运算符的性质。
-
用于类对象的运算符一般必须重载,但有两个例外,运算符“=”和“&”不必用户重载
-
赋值运算符(=)可以用于每一个类对象,可以利用它在同类对象之间赋值,这是因为系统已经为每一个声明的类冲在了一个赋值运算符,他的作用是逐个复制类的数据成员。但是,
当数据成员中包含指向动态分配内存的指针成员时,就必须用户自己实现重载。
-
地址运算符&也可以不必重载,它能返回类对象在内存中的起始地址
-
从理论上来说,可以将一个运算符重载为执行任意的操作,但应当使重载运算符的功能类似于该运算符作用于标准类型数据所实现的功能(如用“=”实现加法,用“>”实现“大于”的关系的运算)
四、何时将运算符重载函数作为成员函数,何时作为友元函数??
-
C++规定赋值运算符“=”、下标运算符“[]”,函数调用运算符“()”,成员运算符“->”必须作为成员函数重载。
-
流插入运算符“<<”和流提取运算符“>>”、类型转化运算符只能作为类的成员函数。
-
一般将单目运算符和复合运算符重载为成员函数
-
一般将双目运算符重载为友元函数
原因如下: -
如果
将重载函数作为成员函数
,它可以通过this指针自由地访问本类的数据成员,因此可以少写一个函数的参数。但必须要求运算表达式(如c1+c2)中第一个参数(即运算符左侧的操作数)是一个类对象,而且与运算符函数的类型相同。
因此必须通过类的对象去调用该类的成员函数,,而且只有运算符重载函数返回值与该对象同类型,运算结果才有意义。 -
将
双目运算符重载为友元函数
时,由于友元函数不是该类的成员函数,因此在函数的形参列表中必须有两个参数,不能省略
。
五、总结
-
编译器优先取去类里面查找运算符重载函数,如果没有,然后再到全局找合适的运算符重载函数
-
友元是单向的
-
如果A是B的友元函数,不等于B是A的友元函数,B不能访问A的私有成员
-
友元的关系不能传递
-
如果B是A的友元函数,C是B的友元函数,不等云C是A的友元函数。如果想让C是A的友元函数,应当在A类中另外声明。