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引用的使用詳見后續博客。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM