11.1 运算符重载
假如在某个类(sell 类)中使用了operator+()重载运算符。在实际代码如果有以下:
dist=sid+sara;//两个sell类的对象相加
编译器发现,操作数是sell类对象,因此使用相应的运算符函数替换上述运算符
dist=sid.operator+(sara);//两个sell类的对象相加
该函数隐式地使用sid对象(因为它调用了方法),显式地使用了sara 对象(因为它作为参数传递)。
11.2.1 添加加法运算符
将Time类转换为重载的加法运算符,定义一个operator+()成员函数即可
time.h
#ifndef TIME_H
#define TIME_H
class Time{
private:
int hours;
int minutes;
public:
Time();
Time(int h,int m=0);
Time operator+(const Time & t) const;//const函数,没有修改对象本身
}
#endif// TIME_H
time.cpp
#include"time.h"
Time::Time(){
hours=minutes=0;
}
Time::Time(int h,int m){
hours=h;
minutes=m;
}
Time Time::operator+(const Time & t) const{
Time sum;
sum.minutes=minutes+t.minutes;
sum.hours=hours+t.hours+sum.minutes/60;
sum.minutes %=60;
return sum;
}
两种调用方法:
1.
total=code.operator+(fix);//函数调用表示法
2、
total=code+fix;//运算符表示法
两种方法都可行,运算符表示法,运算符左侧对象(code)是调用对象,运算符右边是作为参数被传递的对象。
假如Time类的使用有如下:
t4=t1+t2+t3;
这种是可以通过编译,并且顺利执行的
首先被转换成
t4=t1.operator+(t2+t3);
然后被转换成
t4=t1.operator+(t2.operator+(t3));
函数调用t2.operator+(t3)返回一个Time类对象,后者是t2和t3的和。然后,该对象成为t1.operator+()的参数,该调用返回t1与表示t2和t3之和的Time对象的和。
11.2.2 重载限制
重载的运算符(有些例外情况)不必是成员函数,但必须至少有一个操作数是用户定义的类型。运算符重载有以下限制:
1、重载后的运算符必须至少有一个操作数是用户定义的类型,这将防止用户为标准类型重载运算符。
2、使用运算符时不能违反运算符原来的语法规则,不能修改运算符的优先级
3、不能创新运算符。
4、不能重载以下运算符。
sizeof : sizeof运算符
. :成员运算符
.* :成员指针运算符
:: :作用域解析运算符
?: :条件运算符
typeid :一个RTTI运算符
const_cast :强制类型转换运算符
dynamic_cast:强制类型转换运算符
reinterpret_cast :强制类型转换运算符
static_cast :强制类型转换运算符
5、表11.1 的大多数运算符都可以通过成员或非成员函数进行重载,但是下面的运算符只能通过成员函数进行重载。
= :赋值运算符
() :函数调用运算符
[] :下标运算符
-> :通过指针访问类成员的运算符
除了这些正式限制之外,还有其他的一些明智限制。例如:不要将*运算符重载成交换两个Time对象的数据成员。
11.3 友元
友元有三种:
1、友元函数
2、友元类
3、友元成员函数
11.3.1 创建友元
创建友元函数的第一步是将其原型放在类声明中,并在原型声明前加上关键字friend:
friend Time operator *(double m,const Time & t)
该原型意味着2点:
1、虽然该函数是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用
2、虽然该函数表示成员函数,但是它与成员函数的访问权限相同。
第二步:编写函数定义
因为不是成员函数,因此不要使用Time:: 限定符。另外,不要在定义中使用关键字,定义如下:
Time operator *(double m,const Time & t){
Time res;
res.hour= t.hour* m;
return res;
}
11.3.2 常用的友元:重载<<运算符
1、<<的第一种重载版本
void operator <<(ostream &os; const Time &t){
os<<t.hour<<" hour ,"<<t.minutes <<" minutes";
}
这样可以使用如下语句:
cout<<trip;
2、<<的第二种重载版本
ostream & operator <<(ostream &os; const Time &t){
os<<t.hour<<" hour ,"<<t.minutes <<" minutes";
return os;
}
这样可以使用如下语句:
cout<< " time "<<trip <<"tuesday ";
禁止 隐式类型转换
explicit 禁止隐式类型转换,只允许显式类型转换
11.6.1 转换函数
转换函数是用户定义的,可以像使用强制类型转换那样使用它们。
要转换为typeName类型,需要使用这种形式的转换函数
operator typeName();
注意以下几点:
1、转换函数必须是类方法
2、转换函数不能指定返回类型
3、转换函数不能有参数
例如,转换为double类型的函数原型如下:
operator double();
typeName指出了要转换成的类型,因此不需要指定返回类型。转换函数是类方法意味着;它需要通过对象来调用,从而告知函数要转换的值。因此,函数不需要参数。
class Stone{
private:
double pounds;
public:
operator int ()const;
}
Stone::operator int() const{
return int (pounds+0.5):
}
11.6.2 转换函数和友元函数
Stone 重载加法运算符。
Stone Stone::operator+(const Stone& st )const{
double pds=pounds+st.pounds;
Stone sum(pds);
return sum;
}
将加法作为友元函数实现:
Stone operator+(const Stone& st1,const Stone& st2 )const{
double pds=st1.pounds+st2.pounds;
Stone sum(pds);
return sum;
}
可以提供方法定义或者友元函数定义,但不能都提供。上面任何一种格式都允许这样做:
Stone jenSt(9,12);
Stone benSt(89,12);
Stone total;
total=jenSt+benSt;
另外,如果提供了Stone (double)构造函数,则也可以这样做:
Stone jenSt(9,12);
//Stone benSt(89,12);
double kenD=17.6;
Stone total;
total=jenSt+kenD;
但只有友元函数才允许这样做:
Stone jenSt(9,12);
//Stone benSt(89,12);
double penD=17.6;
Stone total;
total=penD+jenSt;
为了了解其中的原因,将每一种加法都转换为相应的函数调用。首先:
第一个
total=jenSt+benSt;
被转换为:
total=jenSt.operator+(benSt);//成员函数
或者是
total=operator+(jenSt,benSt);//友元函数
第二个
total=jenSt+kenD;
被转换为:
total=jenSt.operator+(kenD);//成员函数
或者是
total=operator+(jenSt,kenD);//友元函数
第三个
total=penD+jenSt;
被转换为:
total=operator+(penD,jenSt);//友元函数
然而不能调用成员函数。将加法语法转换为函数调用将类似于下面这样:
total=penD.operator+(jenSt);// 没有意义的
将加法定义为友元可以让程序更容易适用自动类型转换。原因在于,两个操作数都成为函数参数,因此与函数原型匹配。
仅供学习:来源《C++ primer plus》
侵删