第11章 友元与运算符重载 ·285·
Complex(float r=0,float i=0) {Real=r;Image=i;}
void Show(int i)
{ cout<<\
friend Complex operator + (Complex & ,Complex &); //“+”重载函数为友元函数 friend Complex operator-(Complex &, Complex &); //“-”重载函数为友元函数 friend Complex operator + (Complex &,float); };
Complex operator + (Complex &c1, Complex &c2) { Complex t;
t.Real=c1.Real+c2.Real; t.Image=c1.Image+c2.Image; return t; }
Complex operator-(Complex &c1, Complex &c2) { Complex t;
t.Real=c1.Real-c2.Real; t.Image=c1.Image-c2.Image; return t; }
Complex operator + (Complex &c,float s) { Complex t;
t.Real=c.Real+s; t.Image=c.Image; return t; }
void main(void)
{ Complex c1(25,50),c2(100,200),c3,c4; c1.Show(1); c2.Show(2); c3=c1+c2; //c3=(25+50i)+(100+200i)=125+250i c3.Show(3); c4=c2-c1; //c4=(100+200i)-(25+50i)=75+150i c4.Show(4); c1=c1+200; c1.Show(1); }
程序执行后输出:
c1=25+50i
//c1=25+50i+200=225+50i
第11章 友元与运算符重载
c2=100+200i c3=125+250i c4=75+150i c1=225+50i
·286·
在此例中,“+”与“-”运算符的重载函数均为普通函数,并在复数类中说明成复数类的友元函数。因此在三个运算符重载函数中可以使用复数类对象的私有数据成员,即复数的实部与虚部参加相应的算术运算。
从主函数可以看出,用成员函数与友元函数为运算符重载函数,就运算符的使用来讲是一样,但编译器处理方法是不同的,例如对表达式:c3=c1+c2;的处理是,先将c1+c2变换为对友元函数的调用:operator+(c1,c2);再将函数返回结果即两复数的和t赋给复数c3,因此表达式c3=c1+c2; 实际执行了c3= operator+(c1,c2) 的函数调用及赋值工作。
友元函数与成员函数作为二元运算符重载函数的另一个区别是:
当重载函数为成员函数时,二元运算符的左操作数为调用重载函数的对象。右操作数为实参。
当重载函数为友元函数时,二元运算符的左操作数为调用重载函数的第一个实参。右操作数为第二个实参。
11.2.3 一元运算符的重载
所谓一元运算符是只有一个操作数的运算符,如自加运算符“++”,自减运算符“--”等等。与二元运算符的重载类似,一元运算符重载函数也分为类的成员函数与友元函数两类。
1.一元运算符重载函数为类的成员函数
一元运算符重载函数为类的成员函数的格式: <类型><类名>::operator <一元运算符>(形参) { 函数体}
现对比较典型的一元运算符“++”、“--”进行讨论。对于一元运算符“++”、“--”存在前置与后置问题,因此定义函数时会有所区别。
(1)“++”为前置运算符时,函数格式为: <类型><类名>::operator ++( ) {函数体} (2)“++”为后置运算符时,函数格式为 <类型><类名>::operator ++( int ) {函数体}
由于是用运算符重载函数来实现“++”运算,所以这里的“++”是广义上的增量运算符。在后置运算符重载函数中,形参int仅用作区分前置还是后置,并无实际意义,可以给一个变量名,也可不给出变量名。
【例11.7】定义一个描述时间计数器的类,其三个数据成员分别用于存放时、分和秒。用成员函数重载“++”运算符,实现计数器对象的加1运算。
# include
第11章 友元与运算符重载
class TCount { private:
int Hour,Minute,Second; public:
TCount (int h=0,int m=0,int s=0) //定义缺省值为0的构造函数
{ Hour=h;Minute=m;Second=s;} TCount operator ++( ); //定义“前置++”运算符重载成员函数 TCount operator ++( int ); //定义“后置++”运算符重载成员函数 void Show(int i ) //定义显示时:分:秒的成员函数
·287·
{cout<<\};
TCount TCount ::operator ++ () { Second++;
if (Second==60) { Second=0; t1=*this t1=*this Minute++;
Hour = 10 Hour = 10 this this if (Minute==60)
Minute=25 Minute=25 { Minute=0;
Second=50 Second=51 Hour++;
if (Hour==24) (a) t1自加前的内容 (b) t1自加后的内容
{ Hour=0;} 图11.2 系统为t1分配的内存空间及this指针 } }
return *this; }
TCount TCount::operator++ (int ) { TCount temp=*this;
temp=*this t1=*this Second++;
if (Second==60) Hour = 10 Hour = 10 this { Second=0; Minute=25 Minute=25 Minute++; Second=51 Second=52 if (Minute==60) 临时对象temp 自加后的内容 (a) (b) t1 { Minute=0;
图11.3 t1对象、this指针与临时对象temp Hour++;
if (Hour==24) { Hour=0;} } }
return temp;
第11章 友元与运算符重载
}
void main(void)
{ TCount t1(10,25,50),t2,t3; //定义时间计数器对象t1=10:25:50 t1.Show(1); t2=++t1; t1.Show(1); t2.Show(2); t3=t1++;
·288·
//先加后用,即:先将t1自加,然后将t1赋给t2
//先用后加,即:先将t1赋给t3,然后将t1自加
t1.Show(1); t3.Show(3); }
程序执行后输出:
t1=10:25:50 t1=10:25:51 t2=10:25:51 t1=10:25:52 t3=10:25:51
说明:
(1)TCount为描述时间计数器的类,其数据成员Hour、Minute、Second分别代表时、分、秒。在主函数中定义时间计数器对象t1、t2、t3,t1的初始值为10时25分50秒。
(2)对对象的自加操作“++”,是对时间计数器的秒加1运算。当秒计满60后,将其清0并对分加1。当分计满60后,将其清0并对时加1。当时计满24后,将其清0。
(3)“前置++”运算符重载成员函数的说明
在主函数中执行t2=++t1语句时,先将t1自加,然后将t1赋给t2。该语句操作是通过调用“前置++”运算符重载成员函数来实现的。在执行t2=++t1语句时,编译系统将t2=++t1解释为对重载函数的调用:
t2=t1.operator ++ ();
由于重载函数为对象t1成员函数,所以函数体对Hour、Minute、Second的自加操作就是对t1的数据成员Hour、Minute、Second的自加操作,因而可完成对计数器对象t1的加1操作。
为了实现前置“++”运算,应将加1后的对象值t1作为返回值,即用return t1语句返回当前对象t1值。但在重载函数体内并不能直接使用对象t1,因而无法使用return t1语句。这时必须使用指向当前对象t1的指针this,如图11.2所示。由于*this=t1,所以用return *this 语句可将自加后的t1值返回给调用函数,并赋给对象t2。由于将对象值t1值作为函数返回值,所以重载函数的类型应与t1的类型相同,为TCount类型。
(4)“后置++”运算符重载成员函数的说明
在主函数中执行t3=t1++语句时,先将t1赋给t3,然后将t1自加。该语句操作是通过调用“后置++”运算符重载成员函数来实现的。在执行t3=t1++语句时,编译系统将t3=t1++解释为对重载函数的调用:
第11章 友元与运算符重载 ·289·
t3=t1.operator ++ (1);
为了实现后置“++”运算,应将加1前的对象值t1作为返回值,这时应使用指向当前对象t1的指针this。在后置重载函数中先用TCount类定义一个临时对象temp,并将t1值(即*this值)赋给temp,在函数最后用return temp语句将加1前的t1值返回给函数,并赋给对象t2。如图11.3所示。
(5)用成员函数实现一元运算符的重载时,运算符的左操作数或右操作数为调用重载函数的对象。因为要用到隐含的this指针,所以运算符重载函数不能定义为静态成员函数,因为静态成员函数中没有this指针。
2.一元运算符重载函数为友元函数
重载一元运算符友元函数的一般格式为:
<类型> operator <一元运算符>(类名 &对象) {函数体} 对于“++”、“――”运算符存在前置运算与后置运算的问题,因此,运算符重载函数必须分为两类。以“++”运算符为例,用友元函数来实现“++”运算符的重载时
前置“++”运算符重载的一般格式为:<类型> operator ++ ( 类名 &); 后置“++”运算符重载的一般格式为:<类型> operator ++ ( 类名 &,int );
其中:形参为要实现“++”运算的对象,int 只是用于区分是前置还是后置运算符,并无整型数的含义。
【例11.8】用一个类来描述时间计数器,用三个数据成员分别存放时、分和秒。用友元函数重载“++”运算符,实现计数器对象的加1运算符。
# include
int Hour,Minute,Second; public: TCount()
{ Hour=Minute=Second=0;} TCount (int h,int m,int s) { Hour=h;Minute=m;Second=s;}
friend TCount operator ++(TCount &t ); //定义“前置++”运算符重载友元函数 friend TCount operator ++( TCount &t ,int ); //定义“后置++”运算符重载友元函数 void Show(int i )
{ cout<<\};
TCount operator ++ (TCount & t) { t.Second++;
if (t.Second==60) { t.Second=0; t.Minute++;