對於乙個運算子函式來說,它或者是類的成員,或者至少含有乙個類型別的引數。
1intoperator+(int, int);//
錯誤,不能為int重定義內建運算子
對於乙個過載的運算子來說,其優先順序和結合律與對應的內建運算子保持一致。
1 x==y+z2//永遠等價於
3 x == (y+z)
邏輯與運算、邏輯或運算和逗號運算子的運算物件求值順序規則無法保留下來,所以不建議過載;
盡量明智地使用運算子過載(慎用)
每個運算子在用於內建型別時都有比較明確地含義。當在內建的運算子和我們自己的操作之間存在邏輯對映關係時,運算子過載的效果最好。此時,使用過載的運算子顯然比另乙個名字更自然也更直觀。不過,過分濫用運算子也會使我們的類變得難以理解。
只有當操作的含義對於使用者來說清晰明了時才使用運算子。
成員函式&非成員函式
賦值(=),下標(),呼叫(())和成員訪問箭頭(->)運算子必須是成員;
復合賦值一般來說應該是成員,但並非必須,這一點與賦值運算子略有不同。
改變物件狀態的運算子或者給定型別密切相關的運算子,如遞增、遞減、和解引用運算子,通常應該是成員;
具有對稱性的運算子通常應該是普通的非成員函式。
關於《運算子
best practice:如果存在唯一一種邏輯可靠的《定義,則應該考慮為這個類定義《運算子。如果類同時還包含==,則當且僅當《的定義和==產生的結果一致時才定義《運算子。
關於下標運算子
我們最好同時定義下標運算子的常量版本和非常量版本,當作用於乙個常量物件時,下標運算子返回常量引用以確保我們不會給返回的物件賦值。
1string& 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):呼叫返回型別+引數型別就是一種呼叫形式。所以,兩種不同的可呼叫物件可能共享同一種呼叫形式。
1int 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();
但是乙個問題是:過載函式
1int 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的型別轉換還是比較普遍的現象。
乙個問題:
1int i = 42
;2 cin << i;
因為cin沒有》,所以,cin會轉換成bool型別,然後左移。
為了防止這一情況的發生,c++新標準引入了顯式地型別轉換運算子。
該規定存在乙個例外:如果表示式被用作條件,則編譯器會將顯式地型別轉換自動應用於它。由此,解決這一問題。
二義性型別轉換(要避免)
二義性1:
1structb;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:
1structa2
;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 比較物件...