C++ Primer:第14章 重載運算與類型轉(zhuǎn)換

第14章 重載運算與類型轉(zhuǎn)換

要求 運算符
可以重載 +?-?*?/?%?^?|?~?=?++?--
+=?-=?*=?/=?%=?^=?|=?&=
!?<?>?<=?>=?==?!=?<<?>>?<<=?>>=
->?->*?[]?()?new?new[]?delete?delete[]
不建議重載 ,?&?&&?||
不能重載 ::?.*?.??:
必須是成員函數(shù) =?[]?()?->
建議是成員函數(shù) +=?-=?*=?/=?%=?^=?|=?&=?<<=?>>=
++?--?*
建議是非成員函數(shù) +?-?*?/?%?^?|?~
!?<?>?<=?>=?==?!=
必須是非成員函數(shù) <<?>>
  1. 若已定義perator==,則最好也定義operator!=;若已定義operator<,則最好也定義其它關(guān)系運算符;若類中含有算術(shù)運算符或位運算符,則最好提供對應(yīng)的復(fù)合賦值運算符。
  2. 除重載的函數(shù)調(diào)用運算符operator()外,其它重載運算符不能含有默認實參。

14.1 基本概念

  1. 運算符函數(shù)必須是類的成員或者至少含有一個類類型的參數(shù)。若是成員函數(shù),this綁定到左側(cè)運算對象,其參數(shù)數(shù)量比運算對象數(shù)量少一個。
  2. 重載運算符的優(yōu)先級、結(jié)合律與對應(yīng)的內(nèi)置運算符保持一致,但無法保留求值順序和短路求值屬性。重載運算符可以是成員函數(shù)或非成員函數(shù)。
  3. 只有當(dāng)操作的含義對于用戶來說清晰明了時才重載運算符。若用戶可能對運算符有幾種不同的理解,重載運算符會產(chǎn)生二義性。
// 非成員函數(shù)調(diào)用方法
data1 + data2;
operator+(data1, data2);
// 成員函數(shù)調(diào)用方法
data1 += data2;
data1.operator+=(data2);

14.2 輸入和輸出運算符

  1. 輸入輸出運算符必須是非成員函數(shù),一般被聲明為友元。輸出運算符應(yīng)盡量減少格式化操作,如不應(yīng)該打印換行符。 輸入運算符必須處理輸入可能失敗的情況,而輸出運算符不需要。
  2. 當(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)系運算符

  1. 如果類中同時定義算術(shù)運算符和相關(guān)的復(fù)合賦值運算符,則應(yīng)使用復(fù)合賦值運算符來實現(xiàn)算術(shù)運算符,因為復(fù)合賦值運算符只會修改左側(cè)運算對象,而算術(shù)運算符會創(chuàng)建一個新對象。
  2. 若存在唯一一種邏輯可靠的<定義,則應(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)運算符

  1. 若類包含下標(biāo)運算符,則通常定義兩個版本:一個返回普通引用,另一個是類的常量成員并且返回常量引用。
string &operator[](size_t n);
const string &operator[](size_t n) const;

14.6 遞增和遞減運算符

  1. 定義遞增遞減運算符應(yīng)同時定義前置版本和后置版本。后置版本比前置版本多接受一個int類型的形參。
ConstStrBlobPtr &operator++();
ConstStrBlobPtr &operator--();
ConstStrBlobPtr operator++(int);
ConstStrBlobPtr operator--(int);

14.7 成員訪問運算符

  1. 箭頭運算符只能用于獲取成員,其運算對象必須是指向類對象的指針或重載->的類的對象。
std::string &operator*() const;
std::string *operator->() const;

14.8 函數(shù)調(diào)用運算符

  1. 調(diào)用運算符可以定義多個不同版本,但要求參數(shù)數(shù)量或類型有所區(qū)別。函數(shù)對象即定義調(diào)用運算符的類的對象。函數(shù)對象其行為類似于函數(shù),常用于泛型算法的實參。
  2. lambda被編譯器翻譯成一個含有重載調(diào)用運算符的未命名類的未命名對象。未命名類的調(diào)用運算符默認是const,若lambda被聲明為mutable,則調(diào)用運算符是非const
  3. 若是值捕獲,lambda產(chǎn)生的類必須為捕獲變量創(chuàng)建數(shù)據(jù)成員和構(gòu)造函數(shù)。若是引用捕獲,則編譯器直接使用該引用,而不會創(chuàng)建數(shù)據(jù)成員。
  4. 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)
  1. 標(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>
  1. C++可調(diào)用對象包括函數(shù)、函數(shù)指針、lambda表達式、bind創(chuàng)建的對象、重載調(diào)用運算符的類。不同可調(diào)用對象可能具有相同的調(diào)用形式。
  2. 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)換與運算符

  1. 轉(zhuǎn)換構(gòu)造函數(shù)將實參類型轉(zhuǎn)換成類類型,類型轉(zhuǎn)換運算符將類類型轉(zhuǎn)換成其它類型。轉(zhuǎn)換構(gòu)造函數(shù)和類型轉(zhuǎn)換運算符共同定義類類型轉(zhuǎn)換(用戶定義的類型轉(zhuǎn)換)。
  2. 類型轉(zhuǎn)換函數(shù)必須是類的成員函數(shù),不能聲明返回類型,形參列表必須為空,通常是const。除void外,只要某一類型可以作為函數(shù)返回類型,類型轉(zhuǎn)換運算符便可將類類型轉(zhuǎn)換成該類型。
  3. 顯式的類型轉(zhuǎn)換與顯式構(gòu)造函數(shù)一樣可阻止編譯器作隱式類型轉(zhuǎn)換,但表達式被作為判斷條件時,編譯器會隱式執(zhí)行顯式的類型轉(zhuǎn)換。轉(zhuǎn)換目標(biāo)是bool的類型轉(zhuǎn)換常用作判斷條件,故operator bool一般定義成explicit
  4. 編譯器只允許進行一次類類型轉(zhuǎn)換和一次算術(shù)轉(zhuǎn)換,其順序不限
  5. 若兩個類提供相同的類型轉(zhuǎn)換或類定義多個轉(zhuǎn)換規(guī)則,則可能產(chǎn)生多重轉(zhuǎn)換路徑。故通常不要為類定義相同的類型轉(zhuǎn)換,也不要在類中定義兩個及兩個以上轉(zhuǎn)換源或轉(zhuǎn)換目標(biāo)是算術(shù)類型的轉(zhuǎn)換。
  6. 調(diào)用重載函數(shù)時,若多個用戶定義的類型轉(zhuǎn)換都提供可行匹配,即使其中存在精確匹配,編譯器也認為調(diào)用存在二義性。
  7. 在表達式中,可以通過函數(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ù)。