• 【转】运算符重载的例析


    所谓重载,就是重新赋予新的含义,函数重载就是对一个已有的函数赋予新的含义,使之实现新功能。
    运算符的重载主要存在两种形式,一种是作为类的成员函数进行使用,另一种则是作为类的友元函数进行使用。运算符的重载的形式为:
       返回类型 operator 运算符符号(参数说明)
        {    
               //函数体的内部实现
        }

    例如,能否用“+”号进行两个复数的相加,在C++中不能在程序中直接用运算符“+”对复数进行相加运算,用户必须自己设法实现复数相加。例如用户可以通过定义一个专门的函数来实现复数相加。

    1. /* 
    2. 实现复数类中的运算符重载 
    3. 定义一个复数类重载运算符+、-、*、/,使之能用于复数的加减乘除。 
    4. 方案一:使用类的成员函数完成运算符的重载; 
    5. */  
    6. #include<iostream>  
    7. using namespace std;  
    8.   
    9. class Complex  
    10. {  
    11. private:  
    12.     double real;  
    13.     double imag;  
    14. public:  
    15.     Complex()  
    16.     {  
    17.         real = 0 ; imag = 0 ;  
    18.     }  
    19.     Complex(double r,double i)  
    20.     {  
    21.         real = r ; imag = i ;  
    22.     }  
    23.     Complex operator+(Complex &c2);  
    24.     Complex operator-(Complex &c2);  
    25.     Complex operator*(Complex &c2);  
    26.     Complex operator/(Complex &c2);  
    27.     void display();  
    28. };  
    29.   
    30. //下面定义成员函数  
    31. Complex Complex::operator+(Complex &c2) //定义重载运算符”+“的函数  
    32. {  
    33.     return Complex(this->real+c2.real , this->imag+c2.imag);   //此处this->real就是c1.real  
    34. }  
    35. Complex Complex::operator-(Complex &c2)//定义重载运算符”-“的函数  
    36. {  
    37.     return Complex(this->real-c2.real , this->imag-c2.imag);   //此处this->real就是c1.real  
    38. }  
    39.   
    40. Complex Complex::operator*(Complex &c2)    
    41. {  
    42.     return Complex(this->real*c2.real , this->imag*c2.imag);   //此处this->real就是c1.real    
    43. }  
    44.   
    45. Complex Complex::operator/(Complex &c2)    
    46. {  
    47.     Complex c;        
    48.     c.real = (real*c2.real + imag*c2.imag)/(c2.real*c2.real+c2.imag*c2.imag);        
    49.     c.imag = (-real*c2.imag + imag*c2.real)/(c2.real*c2.real+c2.imag*c2.imag);       
    50.     return c;        
    51. }     
    52.   
    53. void Complex::display()  
    54. {  
    55.     cout<<"("<<real<<","<<imag<<"i)"<<endl;  
    56. }  
    57.   
    58. int main(void)  
    59. {  
    60.     Complex c1(3,4),c2(5,-10),c3;  
    61.     cout<<"c1=";  
    62.     c1.display();  
    63.     cout<<"c2=";  
    64.     c2.display();  
    65.     c3=c1+c2;   // 此处相当于非重载运算符函数中的“c3=c1.Complex_add(c2)  
    66.     //将运算符+重载为类的成员函数后,编译系统会将程序中的表达式c1+c2解释为:c1.operator+(c2)即以c2为实参调用c1的运算符重载函数operator+(Complex&c2),operator+是类的一个函数名  
    67.     cout<<"c1+c2=";  
    68.     c3.display();  
    69.     c3=c1-c2;  
    70.     cout<<"c1-c2=";  
    71.     c3.display();  
    72.     c3=c1*c2;  
    73.     cout<<"c1*c2=";  
    74.     c3.display();  
    75.     c3=c1/c2;  
    76.     cout<<"c1/c2=";  
    77.     c3.display();  
    78.     return 0;  
    79. }  

    运算符重载运算符的运算规则
          ①运算符重载函数也是函数,重载的运算符不会改变运算符的优先级、结合型和参数的个数。
          ②重载运算符不能违反语言的语法规则。
          ③赋值运算符除外,重载运算符可由派生类继承下去。
          ④重载运算符不能使用默认参数。
          ⑤运算符=、()、[]和->等操作符必须定义为类的成员函数,将这些操作符定义为友元函数将在编译时标记为错误。
         
     ⑥C++中不能重载的运算符只有5个:
           .  (成员访问运算符)
           .* (成员指针访问运算符)
           ∷ (域运算符)
           sizeof(长度运算符)
           ?: (条件运算符)

          因为前两个运算符不能重载是为了保证访问成员的功能不能被改变,域运算符和sizeof运算符的运算对象是类型而不是变量或一般表达式,不具重载的特征。
          ⑦友元运算符的参数规则与类成员运算符的参数规则不同,一员运算符必须显示地声明一个参数,二员运算符必须显示地声明两个参数。类成员运算符重载时,参数中隐含了一个this指针。(另外,C++规定,有的运算符(如赋值运算符、下标运算符、函数调用运算符)必须定义为类的成员函数,有的运算符则不能定义为类的成员函数(如流输入“>>”和流输出“<<”运算符、类型转换运算符))。
    重载为类的成员函数时,参数个数=原操作数个数-1(后置++、--除外),它可以通过this指针自由地访问本类的数据成员,可以少写一个函数的参数,但必须要求运算表达式的第一个参数(即运算符左侧的操作数)是一个类对象。
    重载为类的友元函数时,参数个数=原操作数个数,且至少应该有一个自定义类型的形参。

    1. //方案二:使用类的友元函数,而不是类的成员函数,完成上面提及的运算符的重载;  
    2. #include<iostream>  
    3. using namespace std;  
    4.   
    5. class Complex  
    6. {  
    7. private:  
    8.     double real;  
    9.     double imag;  
    10. public:  
    11.     Complex()    //定义构造函数  
    12.     {  
    13.         real = 0 ; imag = 0 ;  
    14.     }  
    15.     Complex(double r,double i)    //构造函数重载  
    16.     {  
    17.         real = r ; imag = i ;  
    18.     }  
    19.     friend Complex operator+(Complex &c1,Complex &c2);  
    20.     friend Complex operator-(Complex &c1,Complex &c2);  
    21.     friend Complex operator*(Complex &c1,Complex &c2);  
    22.     friend Complex operator/(Complex &c1,Complex &c2);  
    23.     void display();  
    24. };  
    25.   
    26. //下面定义友员函数   
    27. Complex operator+(Complex &c1,Complex &c2)  //定义重载运算符”+“的函数  
    28. {  
    29.     return Complex(c1.real+c2.real,c1.imag+c2.imag);  
    30. }  
    31. Complex operator-(Complex &c1,Complex &c2)  //定义重载运算符”-“的函数  
    32. {  
    33.     return Complex(c1.real-c2.real,c1.imag-c2.imag);  
    34. }  
    35. Complex operator*(Complex &c1,Complex &c2)  //定义重载运算符”*“的函数  
    36. {  
    37.     return Complex (c1.real*c2.real,c1.imag*c2.imag);  
    38. }  
    39. Complex operator/(Complex &c1,Complex &c2)  //定义重载运算符”/“的函数  
    40. {  
    41.     return Complex(c1.real/c2.real,c1.imag/c2.imag);  
    42. }  
    43. void Complex::display()  
    44. {  
    45.     cout<<"("<<real<<","<<imag<<"i)"<<endl;  
    46. }  
    47.   
    48. int main(void)  
    49. {  
    50.     cout<<"用友员函数输出的结果是"<<endl;  
    51.     Complex c1(3,4),c2(5,-10),c3;  
    52.     cout<<"c1=";  
    53.     c1.display();  
    54.     cout<<"c2=";  
    55.     c2.display();  
    56.     c3=c1+c2;  
    57.     cout<<"c1+c2=";  
    58.     c3.display();  
    59.     c3=c1-c2;  
    60.     cout<<"c1-c2=";  
    61.     c3.display();  
    62.     c3=c1*c2;  
    63.     cout<<"c1*c2=";  
    64.     c3.display();  
    65.     c3=c1/c2;  
    66.     cout<<"c1/c2=";  
    67.     c3.display();  
    68.     return 0;  
    69. }  

    如想将一个复数和一个整数相加,如c1+i,可以将运算符重载函数作为成员函数,如下面的形式:

    1. Complex Complex::operator +(int &i)   //运算符重载函数作为Complex类的成员函数  
    2. {  
    3.     return Complex(real + i , imag);  
    4. }  

    注意在表达式中重载的运算符“+”左侧应为Complex类的对象,如
    c3=c2+i;
    不能写成
    c3=i+c2;   //运算符“+”的左侧不是类对象,编译出错
    如果出于某种考虑,要求在使用重载运算符时运算符左侧的操作数是整型量(如表达式i+c2,运算符左侧的操作数i是整数),这时是无法利用前面定义的重载运算符的,因为无法调用i.operator+函数。可想而知,如果运算符左侧的操作数属于C++标准类型(如int)或是一个其他类的对象,则运算符重载函数不能作为成员函数,只能作为非成员函数。如果函数需要访问类的私有成员,则必须声明为友元函数。可以在Complex类中声明:

    1. friend Complex operator+(int &i , Complex &c);   //第一个参数可以不是类对象  

    在类外定义友元函数: 

    1. Complex operator+(int &i , Complex &c)  //运算符重载函数不是成员函数  
    2. {  
    3.     return Complex(i + c.real , c.imag);  
    4. }  

    将双目运算符重载为友元函数时,在函数的形参表列中必须有两个参数,不能省略,形参的顺序任意,不要求第一个参数必须为类对象。但在使用运算符的表达式中,要求运算符左侧的操作数与函数第一个参数对应,运算符右侧的操作数与函数的第二个参数对应。如

    1. c3 = i + c2;  //正确,类型匹配  
    2.     c3 = c2 + i;  //错误,类型不匹配  

    如何重载增量运算符 ++ 和 --
        运算符++和—有前置和后置两种形式,如果不区分前置和后置,则使用operator++( )或operator--( )即可;否则,要使用operator++( )或operator--( )来重载前置运算符,使用operator++(int)或operator--(int)来重载后置运算符,调用时,参数int被传递给值0。如下列程序段:

    1. //重载增量运算符 ++ 和 --  
    2. #include<iostream>  
    3. using namespace std;  
    4.   
    5. class Complex  
    6. {  
    7. private:  
    8.     int x;  
    9.     int y;  
    10. public:  
    11.     Complex()    //定义构造函数  
    12.     {  
    13.         x = 0 ; y = 0 ;  
    14.     }  
    15.     Complex(int a,int b)    //构造函数重载  
    16.     {  
    17.         x = a ; y = b ;  
    18.     }  
    19.     void display();  
    20.     Complex operator ++();      //前置自增方式  
    21.     Complex operator ++(int);   //后置自增方式(增加一个int类型的形参)  
    22. };  
    23.   
    24. Complex Complex::operator ++()  
    25. {  
    26.     x = x + 1;  
    27.     y = y + 1;  
    28.     return *this;  
    29. }  
    30. Complex Complex::operator ++(int)  
    31. {  
    32.     Complex temp(*this);  
    33.     x = x + 1;  
    34.     y = y + 1;  
    35.     return temp;  
    36. }  
    37. void Complex::display()    
    38. {    
    39.     cout<<"("<<x<<","<<y<<")"<<endl;    
    40. }  
    41. int main(void)  
    42. {  
    43.     Complex c1(3,4),c2(5,-10),c3;  
    44.     c3 = c1++;  
    45.     cout<<"c1++=";  
    46.     c3.display();  
    47.     c3 = ++c2;  
    48.     cout<<"++c2=";  
    49.     c3.display();  
    50.     return 0;  
    51. }  

      重载流输入运算符和流输出运算符

    istream  类的对象cin;
    ostream类的对象cout;
    如果想直接用“<<”和“>>”输出和输入自己声明的类型的数据,必须对它们重载,对“<<”和“>>”重载的函数形式如下:
    istream & operator >> (istream &,自定义类 &);
    ostream & operator << (ostream &,自定义类 &);

    重载运算符“>>”的函数的第一个参数和函数的类型都必须是istream&类型,第二个参数是要进行输入操作的类。
    重载“<<”的函数的第一个参数和函数的类型都必须是ostream&类型,第二个参数是要进行输出操作的类。
    只能将重载“>>”和“<<”的函数作为友元函数或普通的函数,而不能将它们定义为成员函数。

    实现代码如下:

      1. //增加重载流提取运算符“>>”,用“cin>>”输入复数,用“cout<<”输出复数。  
      2. #include<iostream>  
      3. using namespace std;  
      4.   
      5. class Complex  
      6. {  
      7. private:  
      8.     double real;  
      9.     double imag;  
      10. public:  
      11.     Complex()    //定义构造函数  
      12.     {  
      13.         real = 0 ; imag = 0 ;  
      14.     }  
      15.     Complex(double r,double i)    //构造函数重载  
      16.     {  
      17.         real = r ; imag = i ;  
      18.     }  
      19.     friend istream& operator>>(istream & , Complex & );  
      20.     friend ostream& operator<<(ostream & , Complex & );  
      21. };  
      22.   
      23. //下面定义友员函数   
      24. istream& operator>>(istream & in, Complex &c)  
      25. {  
      26.     cout<<"input real part and imaginary part of complex number:";  
      27.     in>>c.real>>c.imag;  
      28.     return in;  
      29. }  
      30. ostream& operator<<(ostream & out, Complex &c)  
      31. {  
      32.     out<<'('<<c.real<<"+"<<c.imag<<"i)";  
      33.     return out;  
      34. }  
      35.   
      36. int main(void)  
      37. {  
      38.     Complex c1 , c2;  
      39.     cin>>c1>>c2;  
      40.     cout<<"c1="<<c1<<endl;  
      41.     cout<<"c2="<<c2<<endl;  
      42.     return 0;  
      43. }  


    作者:凡程子
    出处:http://www.cnblogs.com/fzhe/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    MongoDB初期学习
    springboot+camunda实现工作流1
    一文带你深入理解位运算
    【林超所长】学科01:熵与热力学重要模型
    PM常用的讨论社区及牛人帖子
    C# 2.0 的特性 总结
    小脚本解决生活问题
    Domain Adaption 之 TCA等算法
    强化学习ddpg算法
    bindkey用法
  • 原文地址:https://www.cnblogs.com/fzhe/p/2939371.html
Copyright © 2020-2023  润新知