C++学习之路—运算符重载(⼆)运算符重载作为类的成员函数
和友元函数
对运算符重载的函数有两种处理⽅式:(1)把运算符重载的函数作为类的成员函数;(2)运算符重载的函数不是类的成员函数,在类中把它声明为友元函数。
1    把运算符重载函数作为类的成员函数
例1:为了便于说明问题,将重载函数的定义重写如下:
1: Complex Complex :: operator + ( Complex& c2 )
2: {
3:    Complex c ;
4:    c.real = real + c2.real ;
5:    c.imag = imag + c2.imag ;
6:return c ;
7: }
有⼈可能会提出这样的疑问:“+”是双⽬运算符,为什么重载函数只有⼀个参数呢?实际上,运算符重载函数应当有两个参数,但是,由于重载函数是Complex类中的成员函数,因此有⼀个参数是隐含的,运算符函数是⽤this指针隐式的访问类对象的成员。可以看到operator+访问了两个对象中的成员,⼀个是this指针指向的对象中的成员,⼀个是形参对象中的成员。
2    把运算符重载函数作为类的友元函数
运算符重载函数除了可以作为类的成员函数外,还可以是⾮成员函数。在有关的类中把它声明为友元函数,即友元运算符重载函数。
例2:将运算符+重载为适⽤于复数加法,重载函数不作为成员函数,⽽放在类外,作为Complex类的友元函数。
1:class Complex
2: {
3:public:
4:    ...
5:friend Complex operator + ( Complex& c1 , Complex& c2 ) ;    //重载函数作为友元函数
6:private:
7:double real ;
8:double imag ;
9: };
10:
11: Complex operator + ( Complex& c1 , Complex& c2 )                    //定义运算符+重载函数指向类成员函数的指针
12: {
13:    Complex c ;
14:    c.real = c1.real + c2.real ;
15:    c.imag = c1.imag + c2.imag ;
16:return c ;
17: }
这个程序和把运算符重载函数作为类的成员函数相⽐,只做了⼀处改动,就是将运算符重载函数作为类外的普通函数,并在Complex类中声明它为友元函数。可以看到运算符重载函数有两个参数。C++编译系统将程序中的表达式 c1 + c2 解释为operator + ( c1 , c2 ) 。
有的读者可能会产⽣疑问:为什么把运算符函数作为友元函数?理由很简单,因为运算符函数要访问Complex类对象中的成员。如果运算符函数不是Complex类的友元函数,⽽是⼀个普通函数,它是没有权利访问Complex类的私有成员的。
3    将运算符重载函数作为类的成员函数和友元函数的区别
如果将运算符重在为类的成员函数,它可以通过this指针⾃由地访问本类的数据成员,因此⾄少可以少写⼀个函数的参数。但必须要求运算表达式中第⼀个参数(即运算符左侧的操作数)是⼀个类对象,⽽且与运算符函数的类型相同。因为必须通过类的对象去调⽤该类的成员函数,⽽且只有运算符的返回值与该对象同类型,运算结果才有意义。
例如在例1中,将运算符+重载为类的成员函数,则表达式 c1+c2中第⼀个参数c1是Complex类对象,运算符函数的返回值的类型也是Complex。
当然这种规定也会带来问题,如想将⼀个复数和⼀个整数相加,如c1+i,可以运算符+作为成员函数,形式如下:
1: Complex Complex :: operator + ( int& i )
2: {
3:return Complex( real+i ,imag ) ;
4: }
则在表达式必须是c3 = c2 + i ;⽽不能写成c3 = i + c2 ;
如果要求程序员时刻记得重载运算符左右的参数类型,显然不是明智的选择。另外如果出于某种考虑,要求运算符左侧的操作数属于
C++的标准类型或是⼀个其他类的对象,则运算符重载函数不能作为成员函数,只能作为⾮成员函数。如果需要访问类的私有成员,则必须声明为友元函数。
如还是将⼀个复数和⼀个整数相加,如c1+i,可以运算符+作为友元函数,形式如下:
在Complex类中声明:
1:friend Complex operator + ( int& i , Complex& c ) ; //第⼀个参数可以不是类对象
2:friend Complex operator + ( Complex& c , int& i ) ;
在类外定义友元函数:
1: Complex operator + ( int& i , Complex& c )
2: {
3:return Complex( al , c.imag ) ;
4: }
5:
6: Complex operator + (  Complex& c , int& i  )
7: {
8:return Complex( al , c.imag ) ;
9: }
经过这样的处理之后,表达式 c3 = i + c2 ;和 c3 = c2 + i ; 都是合法的。编译系统会根据表达式的形式选择调⽤与之匹配的运算符重载函数。当然也可以把⼀个运算符重载函数作为友元函数,另⼀个作为成员函数。但不能两个都作为成员函数,原因显然哈。
究竟把运算符重载函数作为类的成员函数好,还是友元函数好?由于友元函数的使⽤会破坏类的封装,因此,从原则上说,要尽量将运算符函数作为成员函数。但应统筹考虑各⽅⾯的因素,以下提供具体原则,仅供参考:
(1)C++规定,赋值运算符“=”、下标运算符“[]”、函数调⽤运算符“()”、成员运算符“->”必须作为成员函数。
(2)流插⼊运算符“<<”和刘提取运算符“>>”、类型转换运算符只能作为友元函数。
(3)⼀般将单⽬运算符和复合运算符(+=、-=、/=、*=、!=、^=、%=、>>=、<<=)重载为成员函数。
(4)⼀般将双⽬运算符重载为友元函数。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。