轉自:http://c.biancheng.net/cpp/biancheng/view/3011.html
一、C++運算符重載的概念和語法
所謂重載,就是賦予新的含義。函數重載(Function Overloading)可以讓一個函數名有多種功能,在不同情況下進行不同的操作。運算符重載(Operator Overloading)也是一個道理,同一個運算符可以有不同的功能。
實際上,我們已經在不知不覺中使用了運算符重載。例如,+號可以對不同類型(int、float 等)的數據進行加法操作;<<既是位移運算符,又可以配合 cout 向控制台輸出數據。C++ 本身已經對這些運算符進行了重載。
C++ 也允許程序員自己重載運算符,這給我們帶來了很大的便利。
下面的代碼定義了一個復數類,通過運算符重載,可以用+號實現復數的加法運算:
- #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.8);
- complex c2(2.4, 3.7);
- complex c3;
- c3 = c1 + c2;
- c3.display();
- return 0;
- }
運行結果:
6.7 + 9.5i
本例中義了一個復數類 complex,m_real 表示實部,m_imag 表示虛部,第 10 行聲明了運算符重載,第 21 行進行了實現(定義)。認真觀察這兩行代碼,可以發現運算符重載的形式與函數非常類似。
運算符重載其實就是定義一個函數,在函數體內實現想要的功能,當用到該運算符時,編譯器會自動調用這個函數。也就是說,運算符重載是通過函數實現的,它本質上是函數重載。
運算符重載的格式為:
//TODO:
}
operator是關鍵字,專門用於定義重載運算符的函數。我們可以將operator 運算符名稱這一部分看做函數名,對於上面的代碼,函數名就是operator+。
運算符重載函數除了函數名有特定的格式,其它地方和普通函數並沒有區別。
上面的例子中,我們在 complex 類中重載了運算符+,該重載只對 complex 對象有效。當執行c3 = c1 + c2;語句時,編譯器檢測到+號左邊(+號具有左結合性,所以先檢測左邊)是一個 complex 對象,就會調用成員函數operator+(),也就是轉換為下面的形式:
c3 = c1.operator+(c2);
c1 是要調用函數的對象,c2 是函數的實參。
上面的運算符重載還可以有更加簡練的定義形式:
- complex complex::operator+(const complex &A)const{
- return complex(this->m_real + A.m_real, this->m_imag + A.m_imag);
- }
return 語句中的complex(this->m_real + A.m_real, this->m_imag + A.m_imag)會創建一個臨時對象,這個對象沒有名稱,是一個匿名對象。在創建臨時對象過程中調用構造函數,return 語句將該臨時對象作為函數返回值。
在全局范圍內重載運算符
運算符重載函數不僅可以作為類的成員函數,還可以作為全局函數。更改上面的代碼,在全局范圍內重載+,實現復數的加法運算:
- #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++已有運算符的功能,使之能用於對象。
二、C++運算符重載的規則
運算符重載是通過函數重載實現的,概念上大家都很容易理解,這節我們來說一下運算符重載的注意事項。
1) 並不是所有的運算符都可以重載。能夠重載的運算符包括:
+ - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> <<= >>= == != <= >= && || ++ -- , ->* -> () [] new new[] delete delete[]
上述運算符中,[]是下標運算符,()是函數調用運算符。自增自減運算符的前置和后置形式都可以重載。長度運算符sizeof、條件運算符: ?、成員選擇符.和域解析運算符::不能被重載。
2) 重載不能改變運算符的優先級和結合性。假設上一節的 complex 類中重載了+號和*號,並且 c1、c2、c3、c4 都是 complex 類的對象,那么下面的語句:
c4 = c1 + c2 * c3;
等價於:
c4 = c1 + ( c2 * c3 );
乘法的優先級仍然高於加法,並且它們仍然是二元運算符。
3) 重載不會改變運算符的用法,原有有幾個操作數、操作數在左邊還是在右邊,這些都不會改變。例如~號右邊只有一個操作數,+號總是出現在兩個操作數之間,重載后也必須如此。
4) 運算符重載函數不能有默認的參數,否則就改變了運算符操作數的個數,這顯然是錯誤的。
5) 運算符重載函數既可以作為類的成員函數,也可以作為全局函數。
將運算符重載函數作為類的成員函數時,二元運算符的參數只有一個,一元運算符不需要參數。之所以少一個參數,是因為這個參數是隱含的。
例如,上節的 complex 類中重載了加法運算符:
complex operator+(const complex & A) const;
當執行:
c3 = c1 + c2;
會被轉換為:
c3 = c1.operator+(c2);
通過 this 指針隱式的訪問 c1 的成員變量。
將運算符重載函數作為全局函數時,二元操作符就需要兩個參數,一元操作符需要一個參數,而且其中必須有一個參數是對象,好讓編譯器區分這是程序員自定義的運算符,防止程序員修改用於內置類型的運算符的性質。
例如,下面這樣是不對的:
- 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);
- }
它的作用是使一個整數和一個復數相加。
另外,將運算符重載函數作為全局函數時,一般都需要在類中將該函數聲明為友元函數。原因很簡單,該函數大部分情況下都需要使用類的 private 成員。
上節的最后一個例子中,我們在全局范圍內重載了+號,並在 complex 類中將運算符重載函數聲明為友元函數,因為該函數使用到了 complex 類的 m_real 和 m_imag 兩個成員變量,它們都是 private 屬性的,默認不能在類的外部訪問。
6) 箭頭運算符->、下標運算符[ ]、函數調用運算符( )、賦值運算符=只能以成員函數的形式重載。
三、C++重載數學運算符
四則運算符(+、-、*、/、+=、-=、*=、/=)和關系運算符(>、<、<=、>=、==、!=)都是數學運算符,它們在實際開發中非常常見,被重載的幾率也很高,並且有着相似的重載格式。本節以復數類 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) / (c²+d²)] + [(bc-ad) / (c²+d²)]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;
- }
運行結果:
c7 = 35 + 55i
c8 = 15 + 15i
c9 = -450 + 850i
c10 = 1.9 + -0.3i
c3 = 26 + 37i
c4 = -6 + -11i
c5 = 220 + 4460i
c6 = 5.2 + 1.592i
c1 != c2
需要注意的是,我們以全局函數的形式重載了 +、-、*、/、==、!=,以成員函數的形式重載了 +=、-=、*=、/=,而且應該堅持這樣做,不能一股腦都寫作成員函數或者全局函數,具體原因我們將在下節講解。
四、C++重載>>和<<(輸入輸出運算符)
在C++中,標准庫本身已經對左移運算符<<和右移運算符>>分別進行了重載,使其能夠用於不同數據的輸入輸出,但是輸入輸出的對象只能是 C++ 內置的數據類型(例如 bool、int、double 等)和標准庫所包含的類類型(例如 string、complex、ofstream、ifstream 等)。
如果我們自己定義了一種新的數據類型,需要用輸入輸出運算符去處理,那么就必須對它們進行重載。本節以前面的 complex 類為例來演示輸入輸出運算符的重載。
其實 C++ 標准庫已經提供了 complex 類,能夠很好地支持復數運算,但是這里我們又自己定義了一個 complex 類,這樣做僅僅是為了教學演示。
本節要達到的目標是讓復數的輸入輸出和 int、float 等基本類型一樣簡單。假設 num1、num2 是復數,那么輸出形式就是:
cout<<num1<<num2<<endl;
輸入形式就是:
cin>>num1>>num2;
cout 是 istream 類的對象,cin 是 ostream 類的對象,要想達到這個目標,就必須以全局函數(友元函數)的形式重載<<和>>,否則就要修改標准庫中的類,這顯然不是我們所期望的。
重載輸入運算符>>
下面我們以全局函數的形式重載>>,使它能夠讀入兩個 double 類型的數據,並分別賦值給復數的實部和虛部:
- istream & operator>>(istream &in, complex &A){
- in >> A.m_real >> A.m_imag;
- return in;
- }
istream 表示輸入流,cin 是 istream 類的對象,只不過這個對象是在標准庫中定義的。之所以返回 istream 類對象的引用,是為了能夠連續讀取復數,讓代碼書寫更加漂亮,例如:
complex c1, c2;
cin>>c1>>c2;
如果不返回引用,那就只能一個一個地讀取了:
complex c1, c2;
cin>>c1;
cin>>c2;
另外,運算符重載函數中用到了 complex 類的 private 成員變量,必須在 complex 類中將該函數聲明為友元函數:
friend istream & operator>>(istream & in , complex &a);
>>運算符可以按照下面的方式使用:
complex c;
cin>>c;
當輸入1.45 2.34↙后,這兩個小數就分別成為對象 c 的實部和虛部了。cin>> c;這一語句其實可以理解為:
operator<<(cin , c);
重載輸出運算符<<
同樣地,我們也可以模仿上面的形式對輸出運算符>>進行重載,讓它能夠輸出復數,請看下面的代碼:
- ostream & operator<<(ostream &out, complex &A){
- out << A.m_real <<" + "<< A.m_imag <<" i ";
- return out;
- }
ostream 表示輸出流,cout 是 ostream 類的對象。由於采用了引用的方式進行參數傳遞,並且也返回了對象的引用,所以重載后的運算符可以實現連續輸出。
為了能夠直接訪問 complex 類的 private 成員變量,同樣需要將該函數聲明為 complex 類的友元函數:
friend ostream & operator<<(ostream &out, complex &A);
綜合演示
結合輸入輸出運算符的重載,重新實現 complex 類:
- #include <iostream>
- 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 & A, const complex & B);
- friend complex operator-(const complex & A, const complex & B);
- friend complex operator*(const complex & A, const complex & B);
- friend complex operator/(const complex & A, const complex & B);
- friend istream & operator>>(istream & in, complex & A);
- friend ostream & operator<<(ostream & out, complex & A);
- private:
- double m_real; //實部
- double m_imag; //虛部
- };
- //重載加法運算符
- 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;
- }
- //重載減法運算符
- 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;
- }
- //重載乘法運算符
- complex operator*(const complex & A, const complex &B){
- complex C;
- C.m_real = A.m_real * B.m_real - A.m_imag * B.m_imag;
- C.m_imag = A.m_imag * B.m_real + A.m_real * B.m_imag;
- return C;
- }
- //重載除法運算符
- complex operator/(const complex & A, const complex & B){
- complex C;
- double square = A.m_real * A.m_real + A.m_imag * A.m_imag;
- C.m_real = (A.m_real * B.m_real + A.m_imag * B.m_imag)/square;
- C.m_imag = (A.m_imag * B.m_real - A.m_real * B.m_imag)/square;
- return C;
- }
- //重載輸入運算符
- istream & operator>>(istream & in, complex & A){
- in >> A.m_real >> A.m_imag;
- return in;
- }
- //重載輸出運算符
- ostream & operator<<(ostream & out, complex & A){
- out << A.m_real <<" + "<< A.m_imag <<" i ";;
- return out;
- }
- int main(){
- complex c1, c2, c3;
- cin>>c1>>c2;
- c3 = c1 + c2;
- cout<<"c1 + c2 = "<<c3<<endl;
- c3 = c1 - c2;
- cout<<"c1 - c2 = "<<c3<<endl;
- c3 = c1 * c2;
- cout<<"c1 * c2 = "<<c3<<endl;
- c3 = c1 / c2;
- cout<<"c1 / c2 = "<<c3<<endl;
- return 0;
- }
運行結果:
2.4 3.6↙
4.8 1.7↙
c1 + c2 = 7.2 + 5.3 i
c1 - c2 = -2.4 + 1.9 i
c1 * c2 = 5.4 + 21.36 i
c1 / c2 = 0.942308 + 0.705128 i
五、C++重載[ ](下標運算符)
C++ 規定,下標運算符[ ]必須以成員函數的形式進行重載。該重載函數在類中的聲明格式如下:
返回值類型 & operator[ ] (參數);
或者:
const 返回值類型 & operator[ ] (參數) const;
使用第一種聲明方式,[ ]不僅可以訪問元素,還可以修改元素。使用第二種聲明方式,[ ]只能訪問而不能修改元素。在實際開發中,我們應該同時提供以上兩種形式,這樣做是為了適應 const 對象,因為通過 const 對象只能調用 const 成員函數,如果不提供第二種形式,那么將無法訪問 const 對象的任何元素。
下面我們通過一個具體的例子來演示如何重載[ ]。我們知道,有些較老的編譯器不支持變長數組,例如 VC6.0、VS2010 等,這有時候會給編程帶來不便,下面我們通過自定義的 Array 類來實現變長數組。
- #include <iostream>
- using namespace std;
- class Array{
- public:
- Array(int length = 0);
- ~Array();
- public:
- int & operator[](int i);
- const int & operator[](int i) const;
- public:
- int length() const { return m_length; }
- void display() const;
- private:
- int m_length; //數組長度
- int *m_p; //指向數組內存的指針
- };
- Array::Array(int length): m_length(length){
- if(length == 0){
- m_p = NULL;
- }else{
- m_p = new int[length];
- }
- }
- Array::~Array(){
- delete[] m_p;
- }
- int& Array::operator[](int i){
- return m_p[i];
- }
- const int & Array::operator[](int i) const{
- return m_p[i];
- }
- void Array::display() const{
- for(int i = 0; i < m_length; i++){
- if(i == m_length - 1){
- cout<<m_p[i]<<endl;
- }else{
- cout<<m_p[i]<<", ";
- }
- }
- }
- int main(){
- int n;
- cin>>n;
- Array A(n);
- for(int i = 0, len = A.length(); i < len; i++){
- A[i] = i * 5;
- }
- A.display();
- const Array B(n);
- cout<<B[n-1]<<endl; //訪問最后一個元素
- return 0;
- }
運行結果:
5↙
0, 5, 10, 15, 20
33685536
重載[ ]運算符以后,表達式arr[i]會被轉換為:
arr.operator[ ](i);
需要說明的是,B 是 const 對象,如果 Array 類沒有提供 const 版本的operator[ ],那么第 60 行代碼將報錯。雖然第 60 行代碼只是讀取對象的數據,並沒有試圖修改對象,但是它調用了非 const 版本的operator[ ],編譯器不管實際上有沒有修改對象,只要是調用了非 const 的成員函數,編譯器就認為會修改對象(至少有這種風險)。
六、C++重載++和--(自增自減運算符)
自增++和自減--都是一元運算符,它的前置形式和后置形式都可以被重載。請看下面的例子:
- #include <iostream>
- #include <iomanip>
- using namespace std;
- //秒表類
- class stopwatch{
- public:
- stopwatch(): m_min(0), m_sec(0){ }
- public:
- void setzero(){ m_min = 0; m_sec = 0; }
- stopwatch run(); // 運行
- stopwatch operator++(); //++i,前置形式
- stopwatch operator++(int); //i++,后置形式
- friend ostream & operator<<( ostream &, const stopwatch &);
- private:
- int m_min; //分鍾
- int m_sec; //秒鍾
- };
- stopwatch stopwatch::run(){
- ++m_sec;
- if(m_sec == 60){
- m_min++;
- m_sec = 0;
- }
- return *this;
- }
- stopwatch stopwatch::operator++(){
- return run();
- }
- stopwatch stopwatch::operator++(int n){
- stopwatch s = *this;
- run();
- return s;
- }
- ostream &operator<<( ostream & out, const stopwatch & s){
- out<<setfill('0')<<setw(2)<<s.m_min<<":"<<setw(2)<<s.m_sec;
- return out;
- }
- int main(){
- stopwatch s1, s2;
- s1 = s2++;
- cout << "s1: "<< s1 <<endl;
- cout << "s2: "<< s2 <<endl;
- s1.setzero();
- s2.setzero();
- s1 = ++s2;
- cout << "s1: "<< s1 <<endl;
- cout << "s2: "<< s2 <<endl;
- return 0;
- }
運行結果:
s1: 00:00
s2: 00:01
s1: 00:01
s2: 00:01
上面的代碼定義了一個簡單的秒表類,m_min 表示分鍾,m_sec 表示秒鍾,setzero() 函數用於秒表清零,run() 函數是用來描述秒針前進一秒的動作,接下來是三個運算符重載函數。
先來看一下 run() 函數的實現,run() 函數一開始讓秒針自增,如果此時自增結果等於60了,則應該進位,分鍾加1,秒針置零。
operator++() 函數實現自增的前置形式,直接返回 run() 函數運行結果即可。
operator++ (int n) 函數實現自增的后置形式,返回值是對象本身,但是之后再次使用該對象時,對象自增了,所以在該函數的函數體中,先將對象保存,然后調用一次 run() 函數,之后再將先前保存的對象返回。在這個函數中參數n是沒有任何意義的,它的存在只是為了區分是前置形式還是后置形式。
自減運算符的重載與上面類似,這里不再贅述。
七、C++重載new和delete運算符
內存管理運算符 new、new[]、delete 和 delete[] 也可以進行重載,其重載形式既可以是類的成員函數,也可以是全局函數。一般情況下,內建的內存管理運算符就夠用了,只有在需要自己管理內存時才會重載。
以成員函數的形式重載 new 運算符:
void * className::operator new( size_t size ){
//TODO:
}
以全局函數的形式重載 new 運算符:
void * operator new( size_t size ){
//TODO:
}
兩種重載形式的返回值相同,都是void *類型,並且都有一個參數,為size_t類型。在重載 new 或 new[] 時,無論是作為成員函數還是作為全局函數,它的第一個參數必須是 size_t 類型。size_t 表示的是要分配空間的大小,對於 new[] 的重載函數而言,size_t 則表示所需要分配的所有空間的總和。
size_t 在頭文件 <cstdio> 中被定義為
typedef unsigned int size_t;,也就是無符號整型。
當然,重載函數也可以有其他參數,但都必須有默認值,並且第一個參數的類型必須是 size_t。
同樣的,delete 運算符也有兩種重載形式。以類的成員函數的形式進行重載:
void className::operator delete( void *ptr){
//TODO:
}
以全局函數的形式進行重載:
void operator delete( void *ptr){
//TODO:
}
兩種重載形式的返回值都是 void 類型,並且都必須有一個 void 類型的指針作為參數,該指針指向需要釋放的內存空間。
當我們以類的成員函數的形式重載了new 和 delete 操作符,其使用方法如下:
- C * c = new C; //分配內存空間
- //TODO:
- delete c; //釋放內存空間
如果類中沒有定義 new 和 delete 的重載函數,那么會自動調用內建的 new 和 delete 運算符。
