• C++——运算符的重载---以成员函数方式重载---以友元函数方式重载


    一、运算符的重载

      1、运算符的重载

      允许把标准运算符(如+ - * /等运算符)应用于自定义数据类型的对象,可以提高程序的可读性,运算符的重载本质上还是函数重载。运算符仅仅是语法上的方便,它是另一种函数调用的方式,只有在设计涉及的代码更容易写,尤其是更容易读的时候才有必要重载。

      2、实现运算符重载的方式------既然是操作符重载,就必然会访问类的私有成员变量,根据类的封装性要求,除了友元函数外,其他任何外部操作都是违规的,所以不能用普通函数来重载操作符

    • 类的成员函数
    • 友元函数(即类外的普通函数)
    • 普通函数---在极少数的情况下才会使用普通函数,因为普通函数不能直接访问类的私有成员。解决方法是在类中定义公用的设置数据的set函数和读取数据的get函数,在重载函数中调用这些函数去访问类的私有成员。显然这样不好。

      3、运算符重载的原则:

    • 不能重载的运算符有5个:  .  .*  ?: ::  sizeof
    • 运算符重载不允许发明新的运算符
    • 不能改变运算符操作对象的个数
    • 运算符被重载后其优先级与结合性不会改变

      4、友元函数与类成员函数的使用场合:

    • 一般情况下,建议一元运算符使用类的成员函数,二元运算符使用友元函数
      • 运算符的操作需要修改类对象的状态,则使用成员函数。如需要做左值操作数的运算符(=,+=,*=,++,--)
      • 运算时,有数与对象的混合运算时,必须使用友元函数
      • 二元运算中,第一个操作数为非对象时,必须使用友元函数。如输入输出运算符<< >>
    • 具体规则如下:

      5.友元函数与类成员函数的参数与返回值

    • 参数:
      • 当参数不会被改变时,一般采用const引用,
    • 返回值:
      • 如果返回值可能出现在=左边,则只能作为左值,返回非const引用
      • 如果返回值只能出现在=右边,则只能作为右值,返回const型值或const型引用
      • 如果返回值既可能出现在=号左边,也可能出现在=右边,则其返回值必须为左值,返回非const引用。



    二、使用函数、类成员函数、友元函数分别实现复数+运算符的重载

      1、使用函数实现两个复数相加。示例代码如下:

    •  1 class Complex
       2 {
       3     public:
       4         Complex() 
       5         {
       6             real = 0;
       7             imag = 0;
       8         }
       9         
      10         Complex Complex_Add(Complex &);
      11         
      12     private:    
      13         double real;
      14         double imag;
      15 };
      16  
      17 Complex Complex :: Complex_Add(Complex &c2)
      18 {
      19     Complex temp;
      20     temp.real = this->real + c2.real;
      21     temp.imag = this->imag + c2.imag;
      22     
      23     return temp;
      24 }
      25  
      26 int main()
      27 {
      28     Complex c1(3,4),c2(1.2,-4),c3;
      29     c3 = c1.Complex_Add(c2);
      30     return 0;
      31 }
    •  这种调用方式太繁琐而且不直观


      2、使用类成员函数重载运算符+实现复数运算。具体代码如下:

    •  1 class Complex
       2 {
       3     public:
       4         Complex() //无参构造函数
       5         {
       6             real = 0;
       7             imag = 0;
       8         }
       9         Complex(double r, double i) //有参构造函数
      10         {
      11             real  = r;
      12             imag = i;
      13         }
      14         Complex operator + (Complex &c2); //声明重载运算符
      15     private:
      16         double real;
      17         double imag;
      18 };
      19  
      20 Complex Complex::operator +(Complex &c2)
      21 {
      22     Complex C;//定义一个C对象是为了能够连续使用+操作符
      23     C.real = real + c2.real;
      24     C.imag = imag + c2.imag;
      25     return C;
      26 } 
      27 int main()
      28 {
      29     Complex c1(3,4), c2(5,-10), c3;
      30     c3 = c1 + c2; //运算符+ 用于复数运算
      31     return 0;
      32 }
    • 主函数在执行c1+c2语句时,调用了运算符重载函数operator+()函数

    • 相当于c1.operaor+(c2);

      3、使用友元函数重载运算符+实现复数的相加。具体代码如下:

    •  1 class Complex
       2 {
       3     public:
       4         Complex()
       5         {
       6             real = 0;
       7             imag = 0;
       8         }
       9         Complex(double r, double i)
      10         {
      11             real  = r;
      12             imag = i;
      13         }
      14         friend Complex operator + (Complex &c1, Complex &c2); //声明重载运算符
      15     private:
      16         double real;
      17         double imag;
      18 };
      19  
      20 Complex operator +(Complex &c1,Complex &c2)
      21 {    return Complex(c1.real + c2.real, c1.imag + c2.imag);//直接调用复制构造函数
      22 } 
      23 int main()
      24 {
      25     Complex c1(3,4), c2(5,-10), c3;
      26     c3 = c1 + c2; //运算符+ 用于复数运算 
      27     return 0;
      28 }

       必须是complex的对象才可以相加。如果是实数与complex对象相加,则实数会被默认的构造函数强制转换为虚部为0的复数进行相加。




    三、成员函数重载与友元函数重载的区别:

      1、成员函数与友元函数的区别

    • 成员函数:可以通过this指针访问本类的成员,可以少写一个参数,但是表达式左边的的第一个参数必须是类对象,通过该类对象来调用成员函数。即表达式左侧的左侧运算量就是对象本身。
    • 友元函数:左边一般不是对象。比如输入输出运算符<<  >>一般都要申明为友元重载函数。

      2、成员函数与友元函数对单目运算符双目运算符的比较

    • 对于双目运算符:成员函数重载运算符参数列表需要含有一个参数,而友元函数重载运算符的参数列表需要有两个参数,
    • 对于单目运算符:成员函数重载运算符的参数列表中没有参数,而友元函数重载运算符的参数列表中含有一个参数。

    • 双目运算符可以被重载为友元函数运算符和成员函数运算符。对于复数类+号运算符的重载:当一个整数与一个复数相加时必须使用友元函数。因为使用成员函数表达式左侧必须是对象本身。因此双目运算符一般使用友元函数重载,单目运算符一般使用成员函数重载。

    • 下边列举分别使用成员函数与友元函数重载的++,--,自加加,自减减的例子
      • 使用成员函数以前缀和后缀方式重载运算符--;代码如下:
        •  1 class three
           2 {
           3     public:
           4         three(int a=0,int b=0,int c=0);
           5         void print();
           6         three operator--();//声明自减运算符--重载成员函数(前缀方式) 
           7         three operator--(int);//声明自减运算符--重载成员函数(后缀方式)
           8         private:
           9         int x,y,z; 
          10 };
          11 
          12 three::three(int a,int b,int c)
          13 {
          14     x=a;
          15     y=b;
          16     z=c;
          17 }
          18 three three::operator--()
          19 {
          20     --x;
          21     --y;
          22     --z;
          23     return *this;//返回自减后的当前对象 
          24  } 
          25 three three::operator--(int)
          26 {
          27     three temp(*this); 
          28     x--;
          29     y--;
          30     z--;
          31     return temp;
          32 }
      • 使用友元函数以前缀方式后缀方式重载运算符++。具体代码如下:
        •  1 class three
           2 {
           3     public:
           4         three(int a=0,int b=0,int c=0);
           5         void print();
           6         friend three operator++(three &op);//声明自加运算符++重载友元函数(前缀方式) 
           7         friend three operator++(three &op,int);//声明自加运算符++重载友元函数(后缀方式) 
           8         private:
           9             int x,y,z;
          10  };
          11 
          12  three::three(int a,int b,int c)
          13  {
          14     x=a;
          15     y=b;
          16     z=c;
          17  }
          18 
          19 three operator++(three &op)
          20 {
          21     ++op.x;
          22     ++op.y;
          23     ++op.z;
          24     return op;
          25 }
          26 
          27 three operator++(three &op,int)
          28 {
          29     op.x++;
          30     op.y++;
          31     op.z++;
          32     return op;
          33 }



    四、运算符重载过程中引用于const引用的使用详见后续博客。

  • 相关阅读:
    《Java TCP/IP Socket 编程 》读书笔记之十一:深入剖析socket——TCP套接字的生命周期
    c++实现二分查找
    hadoop序列化机制与java序列化机制对比
    C、C++中“*”操作符和“后++”操作符的优先级
    poj2774之最长公共子串
    Python之美[从菜鸟到高手]--urlparse源码分析
    (程序员面试题)字符串处理之寻找最大不重复子串
    hdu 4782 Beautiful Soupz
    教程Xcode 下编译发布与提交App到AppStore
    云端的ABAP Restful服务开发
  • 原文地址:https://www.cnblogs.com/southcyy/p/10260626.html
Copyright © 2020-2023  润新知