第14章 重載運算與類型轉(zhuǎn)換
要求 |
運算符 |
可以重載 |
+ ?- ?* ?/ ?% ?^ ?| ?~ ?= ?++ ?--
+= ?-= ?*= ?/= ?%= ?^= ?|= ?&=
! ?< ?> ?<= ?>= ?== ?!= ?<< ?>> ?<<= ?>>=
-> ?->* ?[] ?() ?new ?new[] ?delete ?delete[]
|
不建議重載 |
, ?& ?&& ?||
|
不能重載 |
:: ?.* ?. ??:
|
必須是成員函數(shù) |
= ?[] ?() ?->
|
建議是成員函數(shù) |
+= ?-= ?*= ?/= ?%= ?^= ?|= ?&= ?<<= ?>>=
++ ?-- ?*
|
建議是非成員函數(shù) |
+ ?- ?* ?/ ?% ?^ ?| ?~
! ?< ?> ?<= ?>= ?== ?!=
|
必須是非成員函數(shù) |
<< ?>>
|
- 若已定義
perator==
,則最好也定義operator!=
;若已定義operator<
,則最好也定義其它關(guān)系運算符;若類中含有算術(shù)運算符或位運算符,則最好提供對應(yīng)的復(fù)合賦值運算符。
- 除重載的函數(shù)調(diào)用運算符
operator()
外,其它重載運算符不能含有默認實參。
14.1 基本概念
- 運算符函數(shù)必須是類的成員或者至少含有一個類類型的參數(shù)。若是成員函數(shù),
this
綁定到左側(cè)運算對象,其參數(shù)數(shù)量比運算對象數(shù)量少一個。
- 重載運算符的優(yōu)先級、結(jié)合律與對應(yīng)的內(nèi)置運算符保持一致,但無法保留求值順序和短路求值屬性。重載運算符可以是成員函數(shù)或非成員函數(shù)。
- 只有當(dāng)操作的含義對于用戶來說清晰明了時才重載運算符。若用戶可能對運算符有幾種不同的理解,重載運算符會產(chǎn)生二義性。
// 非成員函數(shù)調(diào)用方法
data1 + data2;
operator+(data1, data2);
// 成員函數(shù)調(diào)用方法
data1 += data2;
data1.operator+=(data2);
14.2 輸入和輸出運算符
- 輸入輸出運算符必須是非成員函數(shù),一般被聲明為友元。輸出運算符應(yīng)盡量減少格式化操作,如不應(yīng)該打印換行符。 輸入運算符必須處理輸入可能失敗的情況,而輸出運算符不需要。
- 當(dāng)流中含有錯誤類型的數(shù)據(jù)時讀取操作可能失敗。當(dāng)讀取操作到達文件末尾或遇到輸入流的其它錯誤時也會失敗。當(dāng)讀取操作發(fā)生錯誤時,輸入運算符應(yīng)該負責(zé)將其從錯誤中恢復(fù),如將對象置為合法的狀態(tài)。
istream &operator>>(istream &is, const Sales_data &item)
ostream &operator<<(ostream &os, const Sales_data &item)
14.3 算術(shù)和關(guān)系運算符
- 如果類中同時定義算術(shù)運算符和相關(guān)的復(fù)合賦值運算符,則應(yīng)使用復(fù)合賦值運算符來實現(xiàn)算術(shù)運算符,因為復(fù)合賦值運算符只會修改左側(cè)運算對象,而算術(shù)運算符會創(chuàng)建一個新對象。
- 若存在唯一一種邏輯可靠的
<
定義,則應(yīng)考慮為該類定義<
運算符。若類中同時還包含==
,則當(dāng)且僅當(dāng)<
的定義和==
產(chǎn)生結(jié)果一致時(若兩個對象不相等,則一個對象應(yīng)該小于另一個對象)才能定義<
運算符。
Sales_data &operator+=(const Sales_data &);
Sales_data &operator+(const Sales_data &lhs, const Sales_data &rhs)
bool operator==(const Sales_data &lhs, const Sales_data &rhs)
bool operator<(const StrBlob &lhs, const StrBlob &rhs)
14.4 賦值運算符
StrVec &operator=(std::initializer_list<std::string>);
14.5 下標(biāo)運算符
- 若類包含下標(biāo)運算符,則通常定義兩個版本:一個返回普通引用,另一個是類的常量成員并且返回常量引用。
string &operator[](size_t n);
const string &operator[](size_t n) const;
14.6 遞增和遞減運算符
- 定義遞增遞減運算符應(yīng)同時定義前置版本和后置版本。后置版本比前置版本多接受一個int類型的形參。
ConstStrBlobPtr &operator++();
ConstStrBlobPtr &operator--();
ConstStrBlobPtr operator++(int);
ConstStrBlobPtr operator--(int);
14.7 成員訪問運算符
- 箭頭運算符只能用于獲取成員,其運算對象必須是指向類對象的指針或重載
->
的類的對象。
std::string &operator*() const;
std::string *operator->() const;
14.8 函數(shù)調(diào)用運算符
- 調(diào)用運算符可以定義多個不同版本,但要求參數(shù)數(shù)量或類型有所區(qū)別。函數(shù)對象即定義調(diào)用運算符的類的對象。函數(shù)對象其行為類似于函數(shù),常用于泛型算法的實參。
-
lambda
被編譯器翻譯成一個含有重載調(diào)用運算符的未命名類的未命名對象。未命名類的調(diào)用運算符默認是const
,若lambda
被聲明為mutable
,則調(diào)用運算符是非const
。
- 若是值捕獲,
lambda
產(chǎn)生的類必須為捕獲變量創(chuàng)建數(shù)據(jù)成員和構(gòu)造函數(shù)。若是引用捕獲,則編譯器直接使用該引用,而不會創(chuàng)建數(shù)據(jù)成員。
-
lambda
產(chǎn)生的類不含默認構(gòu)造函數(shù)、賦值運算符及默認析構(gòu)函數(shù);其是否含有默認拷貝構(gòu)造函數(shù)和移動構(gòu)造函數(shù)由捕獲的數(shù)據(jù)成員類型決定。
std::string operator()(void) const
std::string operator()() const
bool operator()(const std::string &s)
- 標(biāo)準(zhǔn)庫定義的函數(shù)對象是模板,使用時需指定類型。函數(shù)對象同樣適用于指針,雖然無法直接比較兩個無關(guān)的指針,但可使用標(biāo)準(zhǔn)庫函數(shù)對象比較兩個無關(guān)指針。
標(biāo)準(zhǔn)庫定義的函數(shù)對象 |
說明(#include <functional> ) |
算術(shù) |
plus<Type> minus<Type> multiplies<Type> divides<Type>
modulus<Type>
negate<Type>
|
關(guān)系 |
equal_to<Type> not_equal_to<Type>
greater<Type> greater_equal<Type>
less<Type> less_equal<Type>
|
邏輯 |
logical_and<Type> logical_or<Type> logical_not<Type>
|
- C++可調(diào)用對象包括函數(shù)、函數(shù)指針、
lambda
表達式、bind
創(chuàng)建的對象、重載調(diào)用運算符的類。不同可調(diào)用對象可能具有相同的調(diào)用形式。
-
function
是模板。不能直接將重載函數(shù)名字存入function
對象,可通過存儲函數(shù)指針或lambda
來消除二義性。
標(biāo)準(zhǔn)庫function 類型 |
示例(#include <functional> ) |
function<T> f;
function<T> f(nullptr);
function<T> f(obj);
|
定義一個存儲可調(diào)用對象的function
|
f; |
若f 含有可調(diào)用對象則返回true ,否則返回false
|
f(args); |
調(diào)用f 中的對象,參數(shù)為args
|
result_type |
可調(diào)用對象的返回類型 |
argument_type
first_argument_type
second_argument_type
|
可調(diào)用對象的參數(shù)類型 |
14.9 重載、類型轉(zhuǎn)換與運算符
- 轉(zhuǎn)換構(gòu)造函數(shù)將實參類型轉(zhuǎn)換成類類型,類型轉(zhuǎn)換運算符將類類型轉(zhuǎn)換成其它類型。轉(zhuǎn)換構(gòu)造函數(shù)和類型轉(zhuǎn)換運算符共同定義類類型轉(zhuǎn)換(用戶定義的類型轉(zhuǎn)換)。
-
類型轉(zhuǎn)換函數(shù)必須是類的成員函數(shù),不能聲明返回類型,形參列表必須為空,通常是
const
。除void
外,只要某一類型可以作為函數(shù)返回類型,類型轉(zhuǎn)換運算符便可將類類型轉(zhuǎn)換成該類型。
- 顯式的類型轉(zhuǎn)換與顯式構(gòu)造函數(shù)一樣可阻止編譯器作隱式類型轉(zhuǎn)換,但表達式被作為判斷條件時,編譯器會隱式執(zhí)行顯式的類型轉(zhuǎn)換。轉(zhuǎn)換目標(biāo)是
bool
的類型轉(zhuǎn)換常用作判斷條件,故operator bool
一般定義成explicit
。
-
編譯器只允許進行一次類類型轉(zhuǎn)換和一次算術(shù)轉(zhuǎn)換,其順序不限。
- 若兩個類提供相同的類型轉(zhuǎn)換或類定義多個轉(zhuǎn)換規(guī)則,則可能產(chǎn)生多重轉(zhuǎn)換路徑。故通常不要為類定義相同的類型轉(zhuǎn)換,也不要在類中定義兩個及兩個以上轉(zhuǎn)換源或轉(zhuǎn)換目標(biāo)是算術(shù)類型的轉(zhuǎn)換。
- 調(diào)用重載函數(shù)時,若多個用戶定義的類型轉(zhuǎn)換都提供可行匹配,即使其中存在精確匹配,編譯器也認為調(diào)用存在二義性。
- 在表達式中,可以通過函數(shù)匹配區(qū)分內(nèi)置運算符和重載運算符,不能通過調(diào)用形式區(qū)分成員函數(shù)和非成員函數(shù)。若類既有轉(zhuǎn)換目標(biāo)是算術(shù)類型的類型轉(zhuǎn)換,又有重載運算符,則會產(chǎn)生內(nèi)置運算符與重載運算符的二義性問題。
// 類型轉(zhuǎn)換運算符一般形式
operator type() const;
// 顯式的類型轉(zhuǎn)換運算符
explicit operator int(){};
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。