運算符重載詳解



1.運算符重載定義:

C++中預定義的運算符的操作對象只能是基本數據類型。但實際上,對於許多用戶自定義類型(例如類),也需要類似的運算操作。這時就必須在C++中重新定義這些運算符,賦予已有運算符新的功能,使它能夠用於特定類型執行特定的操作。運算符重載的實質是函數重載,它提供了C++的可擴展性,也是C++最吸引人的特性之一。

運算符重載是通過創建運算符函數實現的,運算符函數定義了重載的運算符將要進行的操作。運算符函數的定義與其他函數的定義類似,惟一的區別是運算符函數的函數名是由關鍵字operator和其後要重載的運算符符號構成的。運算符函數定義的一般格式如下:

  <返回類型說明符> operator <運算符符號>(<參數表>)

{

     <函數體>

}

 2.運算符重載時要遵循以下規則:

(1) 除了類屬關係運算符"."、成員指針運算符".*"、作用域運算符"::"、sizeof運算符和三目運算符"?:"以外,C++中的所有運算符都可以重載。

(2) 重載運算符限制在C++語言中已有的運算符範圍內的允許重載的運算符之中,不能創建新的運算符。

(3) 運算符重載實質上是函數重載,因此編譯程序對運算符重載的選擇,遵循函數重載的選擇原則。

(4) 重載之後的運算符不能改變運算符的優先級和結合性,也不能改變運算符操作數的個數及語法結構。

(5) 運算符重載不能改變該運算符用於內部類型對象的含義。它只能和用戶自定義類型的對象一起使用,或者用於用戶自定義類型的對象和內部類型的對象混合使用時。

(6) 運算符重載是針對新類型數據的實際需要對原有運算符進行的適當的改造,重載的功能應當與原有功能相類似,避免沒有目的地使用重載運算符。

(7)重載運算符的函數不能有默認的參數,否則就改變了運算符的參數個數,與前面第3點相矛盾了;

(8)重載的運算符只能是用戶自定義類型,否則就不是重載而是改變了現有的C++標準數據類型的運算符的規則了,會引會天下大亂的;

(9)用戶自定義類的運算符一般都必須重載後方可使用,但兩個例外,運算符=&不必用戶重載;

(10)運算符重載可以通過成員函數的形式,也可是通過友元函數,非成員非友元的普通函數。

 

3.運算符重載的形式:

運算符函數重載一般有兩種形式:重載爲類的成員函數和重載爲類的非成員函數。非成員函數通常是友元。(可以把一個運算符作爲一個非成員、非友元函數重載。但是,這樣的運算符函數訪問類的私有和保護成員時,必須使用類的公有接口中提供的設置數據和讀取數據的函數,調用這些函數時會降低性能。可以內聯這些函數以提高性能。)   

1) 成員函數運算符

 運算符重載爲類的成員函數的一般格式爲:

    <函數類型> operator <運算符>(<參數表>)

    {

     <函數體>

    }

 當運算符重載爲類的成員函數時,函數的參數個數比原來的操作數要少一個(後置單目運算符除外),這是因爲成員函數用this指針隱式地訪問了類的一個對象,它充當了運算符函數最左邊的操作數。因此:

(1) 雙目運算符重載爲類的成員函數時,函數只顯式說明一個參數,該形參是運算符的右操作數。

(2) 前置單目運算符重載爲類的成員函數時,不需要顯式說明參數,即函數沒有形參。

(3) 後置單目運算符重載爲類的成員函數時,函數要帶有一個整型形參。

    調用成員函數運算符的格式如下:

    <對象名>.operator <運算符>(<參數>)

    它等價於

    <對象名><運算符><參數>

 例如a+b等價於a.operator +(b)。一般情況下,我們採用運算符的習慣表達方式。

2) 友元函數運算符

 運算符重載爲類的友元函數的一般格式爲:

    friend <函數類型> operator <運算符>(<參數表>)

   {

     <函數體>

    }

當運算符重載爲類的友元函數時,由於沒有隱含的this指針,因此操作數的個數沒有變化,所有的操作數都必須通過函數的形參進行傳遞,函數的參數與操作數自左至右一一對應。

 調用友元函數運算符的格式如下:

    operator <運算符>(<參數1>,<參數2>)

    它等價於

    <參數1><運算符><參數2>

    例如a+b等價於operator +(a,b)

4.兩種重載形式的比較

在多數情況下,將運算符重載爲類的成員函數和類的友元函數都是可以的。但成員函數運算符與友元函數運算符也具有各自的一些特點:

(1) 一般情況下,單目運算符最好重載爲類的成員函數;雙目運算符則最好重載爲類的友元函數。

(2) 以下一些雙目運算符不能重載爲類的友元函數:=、()、[]、->。

(3) 類型轉換函數只能定義爲一個類的成員函數而不能定義爲類的友元函數。

(4) 若一個運算符的操作需要修改對象的狀態,選擇重載爲成員函數較好。

(5) 若運算符所需的操作數(尤其是第一個操作數)希望有隱式類型轉換,則只能選用友元函數。

(6) 當運算符函數是一個成員函數時,最左邊的操作數(或者只有最左邊的操作數)必須是運算符類的一個類對象(或者是對該類對象的引用)。如果左邊的操作數必須是一個不同類的對象,或者是一個內部類型的對象,該運算符函數必須作爲一個友元函數來實現。

(7) 當需要重載運算符具有可交換性時,選擇重載爲友元函數。

5.實例:

 1)用成員函數來重載運算符:

#include <iostream>

using namespace std;

class X{

   int i;

public:

   X(int ii=0){i=ii;}

   X operator   +(const X &rx){

       i+=rx.i;

       return X(i);

   }

   int GetI(){return i;}

};

int main(){

   X a(1),b(3);

   cout<<(a+b).GetI()<<endl;

   return 0;

}

 

2) 用友元函數來重載運算符

說明:此時若用

#include <iostream>

using namespace std;

則會出現如下的錯誤:

fatal error C1001: INTERNAL COMPILER ERROR

所以頭文件用:#include<iostream.h>

 

#include <iostream>

using namespace std;

class Complex{

public:

   Complex(double r=0.0,double i=0.0){

       real=r;

       image=i;

   }

   friend Complex operator+(const Complex&,const Complex&);

   void display();

private:

   double real;

   double image;

};

 

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

   return Complex(c1.real+c2.real,c1.image+c2.image);

}

 

void Complex::display(){

   cout<<"("<<real<<","<<image<<"i)"<<endl;

}

 

int main(){

   Complex c1(3,4),c2(5,-10),c3;

   c3=c1+c2;

   cout<<"c1=";c1.display();

   cout<<"c2=";c2.display();

   cout<<"c1+c2=";c3.display();

   return 0;

}

發佈了50 篇原創文章 · 獲贊 48 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章