C 運算子過載

2021-07-30 23:52:18 字數 3291 閱讀 1934

》運算子函式與運算子過載

運算子過載是計算機語言固有多型性的體現。例如在大多數語言中,運算子「 - 」既表示兩數相減,又表示取乙個數的相反數;既可針對整型資料,又可針對實型、指標等其他型別的資料。c++語言進一步拓展了運算子過載的概念:它不但提供固有的過載,而且還提供過載的手段。

c++把過載的運算子視為特殊的函式,稱為運算子函式。運算子過載就是函式過載的一種特殊情況。與一般過載函式一樣,編譯系統能夠依據使用運算子的不同環境,即引數(運算元)的數量或型別的差異,區分同一運算子的不同含義。

「運算子過載」是針對c++中原有運算子進行的,不能通過過載創造出新的運算子。除了「  [.]  [.*]  [->*]  [::]  [?:] 」運算子外,其他的運算子都可以過載。由於很多符號是一元運算子和二元運算子公用的(如*),為了避免含混,不得為過載的運算子函式設定預設值,因此在呼叫時也就不得省略實參。

除了new和delete這兩個較為特殊的運算子外,任何運算子在作為成員函式過載時不得過載為靜態成員函式。=、、()、->以及所有的型別轉換運算子只能作為成員函式過載,而且不能針對列舉型別運算元進行過載。

運算子函式的函式名由運算子前加關鍵字operator構成,在宣告運算子或呼叫運算子時都可以用這個名稱。因此,可以用兩種不同的方法呼叫運算子函式。

示 例:假定已經作為某個類的成員函式過載了二元運算子+,且c1,c2都是該類的物件。

c1.operator + (c2)    與     c1+c2  

含義相同。如果+作為該類的非成員函式過載,則

operator + (c1,c2)    與 c1+c2

含義相同。

運算子函式作為非成員函式過載時,由於沒有隱含的this指標,因此所有的運算元均出現在形參表中。因此,對於一元運算子,形參表中有乙個引數,代表那個唯一的運算元;對於二元運算子,形參表中有兩個引數,分別代表第一運算元和第二運算元。

過載的運算子保持其原有的操作個數不變。因此,「 * 」既可過載為一元運算子,又可過載為二元運算子;但「 = 」只能過載為二元運算子。

注:過載的運算子還保持其原有的優先順序和結合性不變。

>過載運算子「 ++」

++既可以是字首運算子(前增1),又可以是字尾運算子(後增1)。為了區分這兩種情況,過載這兩個運算子時必須在格式上有所區別:過載字尾++時必須多乙個虛擬引數:int,因此從形式上看像是乙個二元運算子過載。

作為成員函式過載字首++和字尾++:

//字首++

《函式名》 & operator ++ ();

//字尾++

《函式名》 operator ++(int);

注:上述實現方式盡可能多地保留了++原有的屬性

(1)字首++仍然是「先增1後取值」,字尾++仍然是「先取值後增1」

(2)對於字首++,其操作結果仍然是通過所作用的變數提供的,因此返回的操作結果就是對該變數的引用

作為非成員函式過載,唯一的運算元必須作為第一引數提供:

//字首++

friend 《函式名》& operator ++(《函式名》 &《物件名》);

//字尾++

friend 《函式名》& operator ++(《函式名》 &《物件名》,int);

》運算子過載應注意的幾個問題

>過載的運算子應保持其原有的基本語義

過載的運算子應盡可能保持其原有的基本語義,例如針對乙個新的資料型別(乙個新的類)過載了運算子+,則它的含義應當是「相加」、「新增」或「連線」等,而不應當是「相減」或是其他與基本語義不相干的含義。過載的運算子應該體現為原運算子功能在新的資料型別上的延伸,它的使用應當使程式中演算法的表達更流暢、自然,使閱讀程式的人在不借助其他說明資料的情況下就能夠正確理解。如果無法達到這樣的效果,寧可用乙個普通函式來實現相應的功能,也不要讓過載的運算子去勉強承擔哪些更適合於一般函式承擔的功能。

>過載的運算子應盡可能保持其原有的特性

(1)是否要求第一運算元為有左值運算元。左值就是資料的位址,右值就是資料本身。每個資料都有右值,但只有部分資料有左值;典型的有左值資料就是變數,無左值資料就是常量。增量減量運算子(++、--)、賦值運算子(=)、復合賦值運算子(+=、*=等)以及取位址運算子(&)都要求其第一運算元必須是有左值的運算元。過載這些運算子時應盡可能保持這一特性。在將這些運算子作為非成員函式過載(=只能作為成員函式過載)時,對應於第一運算元的第一引數必須宣告為引用引數。

(2)是否修改第一運算元。在(1)中所述的運算子中,除(&)外,都要修改第一運算元。過載這些運算子時應盡可能保持這一特性,函式體中應包含修改第一運算元的操作。

(3)操作的結果是否為有左值資料。在(1)中所述的運算子中,除字尾增量和字尾減量運算子外,其他運算子的操作結果都是有左值資料--實際上就是改變了值的第一運算元。過載這些運算子時應盡可能保持這一特性。因此運算子函式的返回值應宣告為引用;在作為成員函式過載時,第一運算元就該是物件本身,因此函式體中須用return *this;返回;作為非成員函式過載時,第一運算元就是第一引數變數,因此在函式體中須用return 《第一引數變數名》;返回。

(4)保證不改變第二運算元。所有的二元運算子都不會改變第二運算元的值,過載二元運算子時應盡可能保持這一特性。因此,應該把對應與第二運算元的引數(對於成員函式,就是參數列中唯一的引數;對於非成員函式,就是第二引數)宣告為引用,並使用const加以修飾。

>運算子的過載應當配套

某些運算子之間關係密切,存在著某種邏輯上的聯絡,因此若需要過載其中的某乙個,往往就意味著同組的其他運算子也需要過載。例如,過載了+(加),通常也需要過載-(減);過載了==(等於),勢必也就要過載!=(不等於)。

>使用引用引數還是非引用引數

將具有***的運算子過載為非常遠函式時,其第一引數代表第一運算元,應該按引用傳遞,以便使改變第一運算元的值稱為可能。除了這種情況以外,其他引數既可以宣告為非引用引數,也可以宣告為引用引數。

非引用引數的優點是以傳值方式傳遞引數,形參變數只是實參的副本,對形參的修改不會影響實參;在相關物件存在只需乙個實參的建構函式的情況下,可以充分利用表示式處理過程中的自動轉換機制,使表示式顯得更自然。當物件很大或需要深層複製時,非引用引數占用的計算機資源較多,影響引數傳遞的效率。

引用引數的優點是當物件很大或需要深層複製時,可大大減少對資源的占用,提高引數傳遞的效率。但其無法利用系統的自動轉換機制。程式設計者可根據上述資訊並結合具體情況,選擇適當的引數形式。

>作為成員函式過載還是作為非成員函式過載

=、[ ] 、( )  、->以及所有的型別轉換運算子只能作為成員函式過載。如果允許第一運算元不是同類物件,而是其他資料型別,則只能作為非成員函式過載(如輸入輸出流運算子》和《就是這樣的情況)。若希望系統在必要時能夠利用只需要乙個實參的建構函式自動對第一運算元進行轉換,應將該運算子作為非成員函式過載;此種情況下,運算子函式的引數應該是非引用引數。其他情況下運算子一般應作為成員函式過載。

C 運算子過載 過載特殊運算子

賦值運算子用於同類物件間的相互賦值。賦值運算子只能被過載為類的非靜態成員函式,不能過載為友元函式和普通函式。對於使用者自定義的類而言,如果沒有過載賦值運算子,那麼c 編譯器會為該類提供乙個預設的過載賦值運算子成員函式。預設賦值運算子的工作方式是按位對拷,將等到右邊物件的非靜態成員拷貝給等號左邊的物件...

C 運算子過載賦值運算子

自定義類的賦值運算子過載函式的作用與內建賦值運算子的作用類似,但是要要注意的是,它與拷貝建構函式與析構函式一樣,要注意深拷貝淺拷貝的問題,在沒有深拷貝淺拷貝的情況下,如果沒有指定預設的賦值運算子過載函式,那麼系統將會自動提供乙個賦值運算子過載函式。賦值運算子過載函式的定義與其它運算子過載函式的定義是...

C 運算子過載轉換運算子

為什麼需要轉換運算子?大家知道對於內建型別的資料我們可以通過強制轉換符的使用來轉換資料,例如 int 2.1f 自定義類也是型別,那麼自定義類的物件在很多情況下也需要支援此操作,c 提供了轉換運算子過載函式 它使得自定義類物件的強轉換成為可能。轉換運算子的生命方式比較特別,方法如下 operator...