1. 程式人生 > >類和物件(17)—— 操作符過載

類和物件(17)—— 操作符過載

1、操作符過載的基本語法

  所謂過載,就是重新賦予新的含義。函式過載就是對一個已有的函式賦予新的含義,使之實現新功能,因此,一個函式名就可以用來代表不同功能的函式,也就是”一名多用”。

  運算子也可以過載。實際上,我們已經在不知不覺之中使用了運算子過載。例如,大家都已習慣於用加法運算子”+”對整數、單精度數和雙精度數進行加法運算,如5+8,5.8+3.67等,其實計算機對整數、單精度數和雙精度數的加法操作過程是很不相同的,但由於C++已經對運算子”+”進行了過載,所以就能適用於int,float,doUble型別的運算。

  又如”<<“是C++的位運算中的位移運算子(左移),但在輸出操作中又是與流物件cout配合使用的流插入運算子,”>>“也是位移運算子(右移),但在輸入操作中又是與流物件cin配合使用的流提取運算子。這就是運算子過載(operator overloading)。C++系統對”<<“和”>>“進行了過載,使用者在不同的場合下使用它們時,作用是不同的。對”<<“和”>>“的過載處理是放在標頭檔案stream中的。因此,如果要在程式中用”<<“和”>>”作流插入運算子和流提取運算子,必須在本檔案模組中包含標頭檔案stream(當然還應當包括”using namespace std“)。現在要討論的問題是:使用者能否根據自己的需要對C++已提供的運算子進行過載,賦予它們新的含義,使之一名多用。

   運算子過載的本質是函式過載。

   過載函式的一般格式如下:

函式型別 operator操作符名稱 (形參列表)
{
    過載實體;
}

  operator 運算子名稱 在一起構成了新的函式名。比如

const Complex operator+(const Complex &c1, const Complex &c2);

  我們會說,operator+ 過載了過載了運算子+。

 

2、操作符過載的規則

 

(1)C++不允許使用者自己定義新的運算子,只能對已有的 C++運算子進行過載。

 

  例如,有人覺得 BASIC 中用“* *”作為冪運算子很方便,也想在 C++中將“**”定義為冪運算子,用“3* *5”表示 35,這是不行。

 

(2)C++允許過載的運算子

 

  C++中絕大部分運算子都是可以被過載的。

 

 

   不能過載的運算子只有 4 個:

 

 

  前兩個運算子不能過載是為了保證訪問成員的功能不能被改變,域運算符合sizeof 運算子的運算物件是型別而不是變數或一般表示式,不具備過載的特徵。

 

(3)過載不能改變運算子運算物件(即運算元)的個數。

 

  如,關係運算符“>”和“<”等是雙目運算子,過載後仍為雙目運算子,需要兩個引數。運算子”+“,”-“,”*“,”&“等既可以作為單目運算子,也可以作為雙目運算子,可以分別將它們過載為單目運算子或雙目運算子。
(4)過載不能改變運算子的優先級別。

 

  例如”*“和”/“優先順序高於”+“和”-“,不論怎樣進行過載,各運算子之間的優先順序不會改變。有時在程式中希望改變某運算子的優先順序,也只能使用加括號的方法 強制改變過載運算子的運算順序。

 

(5)過載不能改變運算子的結合性。

 

  如,複製運算子”=“是右結合性(自右至左),過載後仍為右結合性。

 

(6)過載運算子的函式不能有預設的引數

 

  否則就改變了運算子引數的個數,與前面第(3)點矛盾。

 

(7)過載的運算子必須和使用者定義的自定義型別的物件一起使用,其引數至少應有一 個是類物件(或類物件的引用)。

 

  也就是說,引數不能全部是 C++的標準型別,以防止使用者修改用於標準型別資料成 員的運算子的性質,如下面這樣是不對的:

 

  複製程式碼 程式碼如下:

 

int operator + (int a,int b)

{
  return(a-b);

}

 

 

 

  原來運算子+的作用是對兩個數相加,現在企圖通過過載使它的作用改為兩個數相 減。如果允許這樣過載的話,如果有表示式 4+3,它的結果是 7 還是 1 呢?顯然,這是 絕對要禁止的。

 

(8)用於類物件的運算子一般必須過載,但有兩個例外,運算子”=“和運算子”&“不 必使用者過載。

 

複製運算子”=“可以用於每一個類物件,可以用它在同類物件之間相互賦值。因 為系統已為每一個新宣告的類過載了一個賦值運算子,它的作用是逐個複製類中的資料 成員地址運算子&也不必過載,它能返回類物件在記憶體中的起始地址。
(9)應當使過載運算子的功能類似於該運算子作用於標準型別資料時候時所實現的功能。

 

  例如,我們會去過載”+“以實現物件的相加,而不會去過載”+“以實現物件相減的功能,因為這樣不符合我們對”+“原來的認知。

 

(10)運算子過載函式可以是類的成員函式,也可以是類的友元函式,還可以是既非類 的成員函式也不是友元函式的普通函式。

 

 

案例一:複數相加

普通方法實現複數相加

  利用全域性函式實現:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a,int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << ")" << endl;
    }

    friend Complex complexAdd(Complex &c1, Complex&c2);
private:
    int a;//實部
    int b;//虛部
};

Complex complexAdd(Complex &c1, Complex&c2)
{
    Complex temp(c1.a + c2.a, c1.b + c2.b);
    return temp;
}

int main(void)
{
    Complex c1(1,2);
    Complex c2(3,4);

    c1.printComplex();
    c2.printComplex();

    Complex c3 = complexAdd(c1, c2);
    c3.printComplex();

    return 0;
}

  利用成員函式實現:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a,int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << ")" << endl;
    }
    Complex complexAdd(Complex&another)
    {
        Complex temp(this->a + another.a, this->b + another.b);
        return temp;
    }

private:
    int a;//實部
    int b;//虛部
};

int main(void)
{
    Complex c1(1,2);
    Complex c2(3,4);

    c1.printComplex();
    c2.printComplex();

    Complex c3=c1.complexAdd(c2);
    c3.printComplex();

    return 0;
}

操作符過載方法實現複數相加:

   利用全域性函式實現:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a,int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    friend Complex operator+(Complex &c1, Complex &c2);

private:
    int a;//實部
    int b;//虛部
};

Complex operator+(Complex &c1, Complex &c2)
{
    Complex temp(c1.a + c2.a, c1.b + c2.b);
    return temp;
}

int main(void)
{
    Complex c1(1,2);
    Complex c2(3,4);

    c1.printComplex();
    c2.printComplex();

    Complex c3 = c1 + c2;//等同於Complex c3=operator+(c1, c2);
    c3.printComplex();

    return 0;
}

  利用成員函式實現:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a,int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    Complex operator+(Complex &another)
    {
        Complex temp(this->a + another.a, this->b + another.b);
        return temp;
    }

private:
    int a;//實部
    int b;//虛部
};


int main(void)
{
    Complex c1(1,2);
    Complex c2(3,4);

    c1.printComplex();
    c2.printComplex();

    Complex c3 = c1 + c2;//等同於Complex c3=c1.operator+(c2);
    c3.printComplex();

    return 0;
}

 

 

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    friend Complex & operator+=(Complex &c1,Complex &c2);

private:
    int a;//實部
    int b;//虛部
};

Complex & operator+=(Complex &c1,Complex &c2)
{
    c1.a += c2.a;
    c1.b += c2.b;

    return c1;
}

int main(void)
{
    Complex c1(1, 2);
    Complex c2(3, 4);

    c1.printComplex();//(1, 2i)    
    c2.printComplex();//(3, 4i)

    (c1 += c2) += c2;
    c1.printComplex();//(7, 10i)
    c2.printComplex();//(3, 4i)

    return 0;
}

 

 

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    Complex& operator+=(Complex &another)
    {
        this->a += another.a;
        this->b += another.b;

        return *this;
    }

private:
    int a;//實部
    int b;//虛部
};


int main(void)
{
    Complex c1(1, 2);
    Complex c2(3, 4);

    c1.printComplex();//(1, 2i)    
    c2.printComplex();//(3, 4i)

    (c1 += c2) += c2;
    c1.printComplex();//(7, 10i)
    c2.printComplex();//(3, 4i)

    return 0;
}