zoukankan      html  css  js  c++  java
  • C++学习之路—运算符重载(二)运算符重载作为类的成员函数和友元函数

    (根据《C++程序设计》(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 

        对运算符重载的函数有两种处理方式:(1)把运算符重载的函数作为类的成员函数;(2)运算符重载的函数不是类的成员函数,在类中把它声明为友元函数。

    1    把运算符重载函数作为类的成员函数

        在上一篇博客(http://www.cnblogs.com/hust-ghtao/p/3525522.html)中,运算符重载函数 operator + 就是属于这种形式,它是Complex类中的成员函数。下面对这种方式进行分析。

        例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( i+c.real , c.imag ) ;
       4: }
       5:  
       6: Complex operator + (  Complex& c , int& i  )
       7: {
       8:     return Complex( i+c.real , c.imag ) ;
       9: }

    经过这样的处理之后,表达式 c3 = i + c2 ;和 c3 = c2 + i ; 都是合法的。编译系统会根据表达式的形式选择调用与之匹配的运算符重载函数。当然也可以把一个运算符重载函数作为友元函数,另一个作为成员函数。但不能两个都作为成员函数,原因显然哈。

        究竟把运算符重载函数作为类的成员函数好,还是友元函数好?由于友元函数的使用会破坏类的封装,因此,从原则上说,要尽量将运算符函数作为成员函数。但应统筹考虑各方面的因素,以下提供具体原则,仅供参考:

        (1)C++规定,赋值运算符“=”、下标运算符“[]”、函数调用运算符“()”、成员运算符“->”必须作为成员函数。

        (2)流插入运算符“<<”和刘提取运算符“>>”、类型转换运算符只能作为友元函数。

        (3)一般将单目运算符和复合运算符(+=、-=、/=、*=、!=、^=、%=、>>=、<<=)重载为成员函数。

        (4)一般将双目运算符重载为友元函数。

  • 相关阅读:
    HTML页面跳转的5种方法
    利用jquery来进行表单的多向提交
    HTML设置超链接字体颜色和点击后的字体颜色
    bootstrap精简教程
    类型的转换的神秘
    [转载] mysql 索引中的USING BTREE 的意义
    [转载]WeeksInAYear、WeeksInYear、DaysInAYear、DaysInAMonth、DaysInYear、DaysInMonth
    范围内取随机数
    [转载]asp.net中,<%#%>,<%=%>和<%%>分别是什么意思,有什么区别
    [转载]localStorage使用总结
  • 原文地址:https://www.cnblogs.com/hust-ghtao/p/3527595.html
Copyright © 2011-2022 走看看