Chapter14 過載運算子

2022-05-03 17:45:10 字數 3828 閱讀 1252

對於乙個運算子函式來說,它或者是類的成員,或者至少含有乙個類型別的引數。

1

intoperator+(int, int);//

錯誤,不能為int重定義內建運算子

對於乙個過載的運算子來說,其優先順序和結合律與對應的內建運算子保持一致。

1 x==y+z2//

永遠等價於

3 x == (y+z)

邏輯與運算、邏輯或運算和逗號運算子的運算物件求值順序規則無法保留下來,所以不建議過載;

盡量明智地使用運算子過載(慎用)

每個運算子在用於內建型別時都有比較明確地含義。當在內建的運算子和我們自己的操作之間存在邏輯對映關係時,運算子過載的效果最好。此時,使用過載的運算子顯然比另乙個名字更自然也更直觀。不過,過分濫用運算子也會使我們的類變得難以理解。

只有當操作的含義對於使用者來說清晰明了時才使用運算子。

成員函式&非成員函式

賦值(=),下標(),呼叫(())和成員訪問箭頭(->)運算子必須是成員;

復合賦值一般來說應該是成員,但並非必須,這一點與賦值運算子略有不同。

改變物件狀態的運算子或者給定型別密切相關的運算子,如遞增、遞減、和解引用運算子,通常應該是成員;

具有對稱性的運算子通常應該是普通的非成員函式。

關於《運算子

best practice:如果存在唯一一種邏輯可靠的《定義,則應該考慮為這個類定義《運算子。如果類同時還包含==,則當且僅當《的定義和==產生的結果一致時才定義《運算子。

關於下標運算子

我們最好同時定義下標運算子的常量版本和非常量版本,當作用於乙個常量物件時,下標運算子返回常量引用以確保我們不會給返回的物件賦值。

1

string& operator

(size_t n);

2const

string& operator (size_t n) const;

關於箭頭運算子

point->mem:point必須是指標型別或是過載了operator->的類物件。

根據point的不同,point->mem等價於:

1.(*point).mem;//point是指標型別

2.point.operator()->mem;//point是類的乙個物件。

那麼這一表示式是如何執行的呢?

如果point是指標,則執行(1);

如果point是類物件,則使用point.operator->()的結果來獲取mem;其中,如果該結果是乙個指標,則執行第1步;如果該結果本身是過載了operator->()的物件,則重複執行(2)

lambda與函式物件

預設情況下,lambda產生的類不能改變它捕獲的變數,所以函式呼叫操作符是乙個const成員函式。

lambda表示式產生的類不含預設建構函式、賦值運算子及預設析構函式,它是否含有預設的拷貝/移動建構函式則通常視捕獲的資料成員型別而定。

可呼叫物件與function

呼叫形式(call signature):呼叫返回型別+引數型別就是一種呼叫形式。所以,兩種不同的可呼叫物件可能共享同一種呼叫形式。

1

int add(int i, int j)

2 auto mod = (int i, int j) ;

3struct

divide

46 };

假設我們要將這些可呼叫物件統一到函式表中

1 mapbinops;

2 binops.insert();

3 binops.insert();//

錯誤,mod不是函式指標

如何解決這一問題?

function標準庫

1 map>binops;

2 binops.insert();

3 binops.insert();

但是乙個問題是:過載函式

1

int add(int i, int j)

2 sale_data add(const sale_data&, const sale_data&);

3 map>binops;

4 binops.insert();//

哪個add?

兩種解決方法:

1 binops.insert();2//

或者3 binops.insert( });

型別轉換

之前我們通過轉換建構函式來實現了使用者定義的型別轉換。

現在我們提供另一種方法:定義型別轉換運算子。

operator type() const;

乙個型別轉換函式必須是類的成員函式;它不能宣告返回型別,形參列表也必須為空。通常應該是const。

之前我們提到過:編譯器一次只能執行一次使用者定義的型別轉換,但是隱式的使用者型別轉換可以置於乙個標準(內建)型別轉換之前或之後。

避免過度使用型別轉換函式:除非兩種型別之間存在明確地一對一對映

在實踐中,類很少提供型別轉換運算子。在大多數情況下,如果型別轉換自動發生,使用者可能會感覺比較意外,而不是感覺受到了幫助。然而這條經驗法則存在一種例外情況:對於類來說,定義向bool的型別轉換還是比較普遍的現象

乙個問題:

1

int i = 42

;2 cin << i;

因為cin沒有》,所以,cin會轉換成bool型別,然後左移。

為了防止這一情況的發生,c++新標準引入了顯式地型別轉換運算子。

該規定存在乙個例外:如果表示式被用作條件,則編譯器會將顯式地型別轉換自動應用於它。由此,解決這一問題

二義性型別轉換(要避免)

二義性1:

1

structb;2

structa3

;7structb8

;11 a f(const a&);

12b b;

13 a a = f(b);//

究竟是f(b::oprator a())還是f(a::a(const b&))

二義性2:

1

structa2

;8void f2(long

double);9

a a;

10 f2(a);//

轉換為int還是double?

11long

lg;12 a a2(lg);//

a::a(int)還是a::a(double)

由此:不要令兩個類執行相同的型別轉換;(只有a轉換為b,或者b轉換為a)

避免轉換目標是內建算術型別的轉換。特別是當你已經定義了乙個轉換為算術型別的轉換時,接下來:

不要再定義接受算術型別的過載運算子;

不要再定義轉換到多種型別的型別轉換。

一言以蔽之:除了顯式地向bool型別轉換,我們應該盡量避免定義型別轉換函式並盡可能限制那些「顯然正確」的飛顯式建構函式

過載函式與過載運算子的乙個不同點是

具有相同名字的成員函式和非成員函式不會彼此過載。

而a sym b可能是 a.operatorsym(b)或者operatorsym(a,b)

所以,函式匹配過程中,成員函式和非成員函式都應該考慮在內。

14 過載運算子和型別轉換

過載運算和型別轉換 輸入輸出運算子過載 當流讀取資料時發生錯誤,輸入運算子應該負責從錯誤裡面恢復 算數運算子和關係運算子 下標運算子 可以通過位置訪問元素的一種方法,通常需要定義下表運算子operator,下標運算子必須是成員函式.下標運算子應該包含兩個版本,乙個返回普通引用,另乙個是類的常量成員,...

過載運算子

題目描述 定義乙個矩形類,資料成員包括左下角和右上角座標,定義的成員函式包括必要的建構函式 輸入座標的函式,實現矩形加法,以及計算並輸出矩形面積的函式。要求使用提示中給出的測試函式並不得改動。兩個矩形相加的規則是 決定矩形的對應座標分別相加,如 左下角 1,2 右上角 3,4 的矩形,與 左下角 2...

過載運算子

include include using namespace std class test test const int a v a test const test t1 v t1.v 以下過載小於號 比較兩個物件的大小 bool operator const test t1 const 比較物件...