以下內容源于C語言中文網的學習與整理,非原創,如有侵權請告知刪除。
一、運算符重載的含義
所謂重載,就是賦予新的含義。函數重載(Function Overloading)可以讓一個函數名有多種功能,在不同情況下進行不同的操作。運算符重載(Operator Overloading)也是一個道理,同一個運算符可以有不同的功能。
二、運算符重載的格式
運算符重載的格式為:
返回值類型 operator 運算符名稱 (形參表列)
{ //TODO:
}
(1)operator
是關鍵字,專門用來定義一個函數(運算符重載函數)。可以將 “operator 運算符名稱
”這一部分看做函數名。比如對于上面的代碼,函數名就是operator+
。
(2)運算符重載函數,除了函數名有特定的格式外,其它地方和普通函數并沒有區別。?
三、簡單的例子說明
例子1:運算符重載函數作為成員函數?
#include<iostream>using namespace std;class complex {
public:complex();complex(double real, double imag);
public:complex operator+ (const complex &A) const;void display() const;
private:double m_real;double m_imag;};complex::complex() :m_real(0.0), m_imag(0.0) {}
complex::complex(double real, double imag) : m_real(real), m_imag(imag) {}complex complex::operator+ (const complex &A) const {complex B;B.m_real = this->m_real + A.m_real;B.m_imag = this->m_imag + A.m_imag;return B;
}void complex::display() const {cout << m_real << "+" << m_imag << "i" << endl;
}int main() {complex c1(4.3, 5.6);complex c2(2.3, 3.7);complex c3;c3 = c1 + c2;c3.display();return 0;
}
上面的例子中,我們在 complex 類中重載了運算符+
,該重載只對 complex 對象有效。
當執行“c3 = c1 + c2;
”語句時,編譯器檢測到+
號左邊(+
號具有左結合性,所以先檢測左邊)是一個 complex 對象,就會調用成員函數operator+()
,也就是轉換為下面的形式:
c1.operator+(c2)
即 c1 這個對象調用了函數operator+
,而 c2 是函數的實參。?
例子2:運算符重載函數作為全局函數
#include <iostream>
using namespace std;class complex{
public:complex();complex(double real, double imag);
public:void display() const;//聲明為友元函數friend complex operator+(const complex &A, const complex &B);
private:double m_real;double m_imag;
};complex operator+(const complex &A, const complex &B);complex::complex(): m_real(0.0), m_imag(0.0){ }
complex::complex(double real, double imag): m_real(real), m_imag(imag){ }
void complex::display() const{cout<<m_real<<" + "<<m_imag<<"i"<<endl;
}//在全局范圍內重載+
complex operator+(const complex &A, const complex &B){complex C;C.m_real = A.m_real + B.m_real;C.m_imag = A.m_imag + B.m_imag;return C;
}int main(){complex c1(4.3, 5.8);complex c2(2.4, 3.7);complex c3;c3 = c1 + c2;c3.display();return 0;
}
因為該運算符重載函數不是 complex 類的成員函數,但是卻用到了 complex 類的 private 成員變量,所以必須在 complex 類中將該函數聲明為友元函數。
當執行“?c3 = c1 + c2;
” 語句時,編譯器檢測到+
號兩邊都是 complex 對象,就會轉換為類似下面的函數調用:c3 = operator+(c1, c2);
總結:雖然運算符重載所實現的功能完全可以用函數替代,但運算符重載使得程序的書寫更加人性化,易于閱讀。運算符被重載后,原有的功能仍然保留,沒有喪失或改變;而通過運算符重載,擴大了C++已有運算符的功能,使之能用于對象。
四、運算符重載時要遵循的規則
1、并不是所有的運算符都可以重載。
2、重載不能改變運算符的優先級和結合性。
3、重載不會改變運算符的用法,原來有幾個操作數、操作數在左邊還是在右邊,這些都不會改變。例如?+
號總是出現在兩個操作數之間,重載后也必須如此。
4、運算符重載函數不能有默認的參數,否則就改變了運算符操作數的個數,這顯然是錯誤的。
5、運算符重載函數既可以作為類的成員函數,也可以作為全局函數。
(1)將運算符重載函數作為類的成員函數時,二元運算符的參數只有一個,一元運算符不需要參數。之所以少一個參數,是因為這個參數是隱含的(比如上面的例子1)。
(2)將運算符重載函數作為全局函數時,二元操作符就需要兩個參數,一元操作符需要一個參數,而且其中必須有一個參數是對象(記憶:運算符重載,是在c++引入對象時才有的概念,所以它的一個參數是對象),好讓編譯器區分這是程序員自定義的運算符,防止程序員修改用于內置類型的運算符的性質。
例如,下面這樣是不對的:
int operator + (int a,int b){return (a-b);
}
+
號原來是對兩個數相加,現在企圖通過重載使它的作用改為兩個數相減, 如果允許這樣重載的話,那么表達式4+3
的結果是 7 還是 1 呢?顯然,這是絕對禁止的。
如果有兩個參數,這兩個參數可以都是對象,也可以一個是對象,一個是C ++內置類型的數據,例如:
complex operator+(int a, complex &c){return complex(a+c.real, c.imag);
}
它的作用是使一個整數和一個復數相加。
(3)另外,將運算符重載函數作為全局函數時,一般都需要在類中將該函數聲明為友元函數。原因很簡單,該函數大部分情況下都需要使用類的 private 成員。
6、箭頭運算符->
、下標運算符[ ]
、函數調用運算符( )
、賦值運算符=
只能以成員函數的形式重載。
五、重載數學運算符(示例)
四則運算符(+、-、*、/、+=、-=、*=、/=)和關系運算符(>、<、<=、>=、==、!=)都是數學運算符,它們在實際開發中非常常見,被重載的幾率也很高,并且有著相似的重載格式。本節以復數類 Complex 為例對它們進行重載,重在演示運算符重載的語法以及規范。
復數能夠進行完整的四則運算,但不能進行完整的關系運算:我們只能判斷兩個復數是否相等,但不能比較它們的大小,所以不能對 >、<、<=、>= 進行重載。下面是具體的代碼:
#include <iostream>
#include <cmath>
using namespace std;//復數類
class Complex{
public: //構造函數Complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag){ }
public: //運算符重載//以全局函數的形式重載friend Complex operator+(const Complex &c1, const Complex &c2);friend Complex operator-(const Complex &c1, const Complex &c2);friend Complex operator*(const Complex &c1, const Complex &c2);friend Complex operator/(const Complex &c1, const Complex &c2);friend bool operator==(const Complex &c1, const Complex &c2);friend bool operator!=(const Complex &c1, const Complex &c2);//以成員函數的形式重載Complex & operator+=(const Complex &c);Complex & operator-=(const Complex &c);Complex & operator*=(const Complex &c);Complex & operator/=(const Complex &c);
public: //成員函數double real() const{ return m_real; }double imag() const{ return m_imag; }
private:double m_real; //實部double m_imag; //虛部
};//重載+運算符
Complex operator+(const Complex &c1, const Complex &c2){Complex c;c.m_real = c1.m_real + c2.m_real;c.m_imag = c1.m_imag + c2.m_imag;return c;
}
//重載-運算符
Complex operator-(const Complex &c1, const Complex &c2){Complex c;c.m_real = c1.m_real - c2.m_real;c.m_imag = c1.m_imag - c2.m_imag;return c;
}
//重載*運算符 (a+bi) * (c+di) = (ac-bd) + (bc+ad)i
Complex operator*(const Complex &c1, const Complex &c2){Complex c;c.m_real = c1.m_real * c2.m_real - c1.m_imag * c2.m_imag;c.m_imag = c1.m_imag * c2.m_real + c1.m_real * c2.m_imag;return c;
}
//重載/運算符 (a+bi) / (c+di) = [(ac+bd) / (c2+d2)] + [(bc-ad) / (c2+d2)]i
Complex operator/(const Complex &c1, const Complex &c2){Complex c;c.m_real = (c1.m_real*c2.m_real + c1.m_imag*c2.m_imag) / (pow(c2.m_real, 2) + pow(c2.m_imag, 2));c.m_imag = (c1.m_imag*c2.m_real - c1.m_real*c2.m_imag) / (pow(c2.m_real, 2) + pow(c2.m_imag, 2));return c;
}
//重載==運算符
bool operator==(const Complex &c1, const Complex &c2){if( c1.m_real == c2.m_real && c1.m_imag == c2.m_imag ){return true;}else{return false;}
}
//重載!=運算符
bool operator!=(const Complex &c1, const Complex &c2){if( c1.m_real != c2.m_real || c1.m_imag != c2.m_imag ){return true;}else{return false;}
}//重載+=運算符
Complex & Complex::operator+=(const Complex &c){this->m_real += c.m_real;this->m_imag += c.m_imag;return *this;
}
//重載-=運算符
Complex & Complex::operator-=(const Complex &c){this->m_real -= c.m_real;this->m_imag -= c.m_imag;return *this;
}
//重載*=運算符
Complex & Complex::operator*=(const Complex &c){this->m_real = this->m_real * c.m_real - this->m_imag * c.m_imag;this->m_imag = this->m_imag * c.m_real + this->m_real * c.m_imag;return *this;
}
//重載/=運算符
Complex & Complex::operator/=(const Complex &c){this->m_real = (this->m_real*c.m_real + this->m_imag*c.m_imag) / (pow(c.m_real, 2) + pow(c.m_imag, 2));this->m_imag = (this->m_imag*c.m_real - this->m_real*c.m_imag) / (pow(c.m_real, 2) + pow(c.m_imag, 2));return *this;
}int main(){Complex c1(25, 35);Complex c2(10, 20);Complex c3(1, 2);Complex c4(4, 9);Complex c5(34, 6);Complex c6(80, 90);Complex c7 = c1 + c2;Complex c8 = c1 - c2;Complex c9 = c1 * c2;Complex c10 = c1 / c2;cout<<"c7 = "<<c7.real()<<" + "<<c7.imag()<<"i"<<endl;cout<<"c8 = "<<c8.real()<<" + "<<c8.imag()<<"i"<<endl;cout<<"c9 = "<<c9.real()<<" + "<<c9.imag()<<"i"<<endl;cout<<"c10 = "<<c10.real()<<" + "<<c10.imag()<<"i"<<endl;c3 += c1;c4 -= c2;c5 *= c2;c6 /= c2;cout<<"c3 = "<<c3.real()<<" + "<<c3.imag()<<"i"<<endl;cout<<"c4 = "<<c4.real()<<" + "<<c4.imag()<<"i"<<endl;cout<<"c5 = "<<c5.real()<<" + "<<c5.imag()<<"i"<<endl;cout<<"c6 = "<<c6.real()<<" + "<<c6.imag()<<"i"<<endl;if(c1 == c2){cout<<"c1 == c2"<<endl;}if(c1 != c2){cout<<"c1 != c2"<<endl;}return 0;
}
需要注意的是,我們以全局函數的形式重載了 +、-、*、/、==、!=,以成員函數的形式重載了 +=、-=、*=、/=,而且應該堅持這樣做,不能一股腦都寫作成員函數或者全局函數,具體原因我們將在下節講解。