重载操作符与转换(上)
重載操作符的作用:
通過(guò)操作符重載,程序員能夠針對(duì)類(lèi)類(lèi)型的操作數(shù)定義不同的操作符版本。程序用移位操作符(>> 和 <<)進(jìn)行輸入輸出,用加號(hào)操作符(+)將兩個(gè) Sales_items 相加。
通過(guò)操作符重載,可以定義大多數(shù)操作符,使它們用于類(lèi)類(lèi)型對(duì)象。明智地使用操作符重載可以使類(lèi)類(lèi)型的使用像內(nèi)置類(lèi)型一樣直觀。標(biāo)準(zhǔn)庫(kù)為容器類(lèi)定義了幾個(gè)重載操作符。這些容器類(lèi)定義了下標(biāo)操作符以訪問(wèn)數(shù)據(jù)元素,定義了 * 和 -> 對(duì)容器迭代器解引用。這些標(biāo)準(zhǔn)庫(kù)的類(lèi)型具有相同的操作符,使用它們就像使用內(nèi)置數(shù)組和指針一樣。允許程序使用表達(dá)式而不是命名函數(shù),可以使編寫(xiě)和閱讀程序容易得多。
cout << "The sum of " << v1 << " and " << v2<< " is " << v1 + v2 << endl;和以下更為冗長(zhǎng)的代碼相比較就能夠看到。如果 IO 使用命名函數(shù),類(lèi)似下面的代碼將無(wú)法避免:
// hypothetical expression if IO used named functionscout.print("The sum of ").print(v1).print(" and ").print(v2).print(" is ").print(v1 + v2).print("\n").flush();重載操作符是具有特殊名稱(chēng)的函數(shù):保留字 operator 后接需定義的操作符號(hào)。像任意其他函數(shù)一樣,重載操作符具有返回類(lèi)型和形參表,如下語(yǔ)句:
Sales_item operator+(const Sales_item&, const Sales_item&);聲明了加號(hào)操作符,可用于將兩個(gè) Sales_item 對(duì)象“相加”并獲得一個(gè) Sales_item 對(duì)象的副本。除了函數(shù)調(diào)用操作符之外,重載操作符的形參數(shù)目(包括成員函數(shù)的隱式 this 指針)與操作符的操作數(shù)數(shù)目相同。函數(shù)調(diào)用操作符可以接受任意數(shù)目的操作數(shù)。
可重載的操作符:
不可重載的操作符:
通過(guò)連接其他合法符號(hào)可以創(chuàng)建新的操作符。例如,定義一個(gè) operator** 以提供求冪運(yùn)算是合法的。
- 重載操作符必須有一個(gè)類(lèi)類(lèi)型操作數(shù)
?用于內(nèi)置類(lèi)型的操作符,其含義不能改變。例如,內(nèi)置的整型加號(hào)操作符不能重定義:
// error: cannot redefine built-in operator for intsint operator+(int, int);也不能為內(nèi)置數(shù)據(jù)類(lèi)型重定義加號(hào)操作符。例如,不能定義接受兩個(gè)數(shù)組類(lèi)型操作數(shù)的 operator+。重載操作符必須具有至少一個(gè)類(lèi)類(lèi)型或枚舉類(lèi)型的操作數(shù)。這條規(guī)則強(qiáng)制重載操作符不能重新定義用于內(nèi)置類(lèi)型對(duì)象的操作符的含義。
- 優(yōu)先級(jí)和結(jié)合性是固定的
操作符的優(yōu)先級(jí)、結(jié)合性或操作數(shù)目不能改變。不管操作數(shù)的類(lèi)型和操作符的功能定義如何,表達(dá)式
x == y +z;總是將實(shí)參 y 和 z 綁定到 operator+,并且將結(jié)果用作 operator== 右操作數(shù)。有四個(gè)符號(hào)(+, -, * 和 &)既可作一元操作符又可作二元操作符,這些操作符有的在其中一種情況下可以重載,有的兩種都可以,定義的是哪個(gè)操作符由操作數(shù)數(shù)目控制。除了函數(shù)調(diào)用操作符 operator() 之外,重載操作符時(shí)使用默認(rèn)實(shí)參是非法的。
- 不具備短路求值特性(作為"&&"和"||"操作符的操作數(shù)表達(dá)式,這些表達(dá)式在進(jìn)行求值時(shí),只要最終的結(jié)果已經(jīng)可以確定是真或假,求值過(guò)程便告終止,這稱(chēng)之為短路求值)
重載操作符并不保證操作數(shù)的求值順序,尤其是,不會(huì)保證內(nèi)置邏輯 AND、邏輯 OR和逗號(hào)操作符的操作數(shù)求值。在 && 和 || 的重載版本中,兩個(gè)操作數(shù)都要進(jìn)行求值,而且對(duì)操作數(shù)的求值順序不做規(guī)定。因此,重載 &&、|| 或逗號(hào)操作符不是一種好的做法。
- 類(lèi)成員與非成員
大多數(shù)重載操作符可以定義為普通非成員函數(shù)或類(lèi)的成員函數(shù)。作為類(lèi)成員的重載函數(shù),其形參看起來(lái)比操作數(shù)數(shù)目少 1。作為成員函數(shù)的操作符有一個(gè)隱含的 this 形參,限定為第一個(gè)操作數(shù)。重載一元操作符如果作為成員函數(shù)就沒(méi)有(顯式)形參,如果作為非成員函數(shù)就有一個(gè)形參。類(lèi)似地,重載二元操作符定義為成員時(shí)有一個(gè)形參,定義為非成員函數(shù)時(shí)有兩個(gè)形參。類(lèi) Sales_item 中給出了成員和非成員二元操作符的良好例子。我們知道該類(lèi)有一個(gè)加號(hào)操作符。因?yàn)樗幸粋€(gè)加號(hào)操作符,所以也應(yīng)該定義一個(gè)復(fù)合賦值(+=)操作符,該操作符將一個(gè) Sales_item 對(duì)象的值加至另一個(gè) Sales_item 對(duì)象。
一般將算術(shù)和關(guān)系操作符定義非成員函數(shù),而將賦值操作符定義為成員:
// member binary operator: left-hand operand bound to implicit this pointerSales_item& Sales_item::operator+=(const Sales_item&);// nonmember binary operator: must declare a parameter for each operandSales_item operator+(const Sales_item&, const Sales_item&);加和復(fù)合賦值都是二元操作符,但這些函數(shù)定義了不同數(shù)目的形參,差異的原因在于 this 指針。當(dāng)操作符為成員函數(shù),this 指向左操作數(shù),因此,非成員 operator+ 定義兩個(gè)形參,都引用 const Sales_item 對(duì)象。即使復(fù)合賦值是二元操作符,成員復(fù)合賦值操作符也只接受一個(gè)(顯式的)形參。使用操作符時(shí),一個(gè)指向左操作數(shù)的指針自動(dòng)綁定到 this,而右操作符限定為函數(shù)的唯一形參。復(fù)合賦值返回一個(gè)引用而加操作符返回一個(gè) Sales_item 對(duì)象,這也沒(méi)什么。當(dāng)應(yīng)用于算術(shù)類(lèi)型時(shí),這一區(qū)別與操作符的返回類(lèi)型相匹配:加返回一個(gè)右值,而復(fù)合賦值返回對(duì)左操作數(shù)的引用。
- 操作符重載和友元關(guān)系
操作符定義為非成員函數(shù)時(shí),通常必須將它們?cè)O(shè)置為所操作類(lèi)的友元。在這種情況下,操作符通常需要訪問(wèn)類(lèi)的私有部分。Sales_item 類(lèi)也是說(shuō)明為何有些操作符需要設(shè)置為友元的一個(gè)好例子。它定義了一個(gè)成員操作符,并且有三個(gè)非成員操作符。有兩個(gè)非成員操作符需要訪問(wèn)私有數(shù)據(jù)成員,需聲明為友元:
class Sales_item {friend std::istream& operator>>(std::istream&, Sales_item&);friend std::ostream& operator<<(std::ostream&, const Sales_item&);public:Sales_item& operator+=(const Sales_item&);};Sales_item operator+(const Sales_item&, const Sales_item&);輸入和輸出操作符需要訪問(wèn) private 數(shù)據(jù)不會(huì)令人驚訝,畢竟,它們的作用是讀入和寫(xiě)出那些成員。另一方面,不需要將加操作符設(shè)置為友元,它可以用 public 成員 operator+= 實(shí)現(xiàn)。
- 使用重載操作符
使用重載操作符的方式,與內(nèi)置類(lèi)型操作數(shù)上使用操作符的方式一樣。假定 item1 和 item2 是 Sales_item 對(duì)象,可以打印它們的和,就像打印兩個(gè) int 的和一樣:
cout << item1 + item2 << endl;這個(gè)表達(dá)式隱式調(diào)用為 Sales_items 類(lèi)而定義的 operator+。也可以像調(diào)用普通函數(shù)一樣調(diào)用重載操作符函數(shù),指定函數(shù)并傳遞適當(dāng)類(lèi)型適當(dāng)數(shù)目的形參:
// equivalent direct call to nonmember operator functioncout << operator+(item1, item2) << endl;這個(gè)調(diào)用與 item1 和 item2 相加的表達(dá)式等效。
調(diào)用成員操作符函數(shù)與調(diào)用任意其他函數(shù)是一樣的:指定運(yùn)行函數(shù)的對(duì)象,然后使用點(diǎn)或箭頭操作符獲取希望調(diào)用的函數(shù),同時(shí)傳遞所需數(shù)目和類(lèi)型的實(shí)參。對(duì)于二元成員操作符函數(shù)的情況,我們必須傳遞一個(gè)操作數(shù):
item1 += item2; // expression based "call"item1.operator+=(item2); // equivalent call to member operator function兩個(gè)語(yǔ)句都將 item2 的值加至 item1。第一種情況下,使用表達(dá)式語(yǔ)法隱式調(diào)用重載操作符函數(shù):第二種情況下,在 item1 對(duì)象上調(diào)用成員操作符函數(shù)。
#include <iostream> #include <string> using namespace std;class Sales_item { public:Sales_item() :product_name("UnNamed"), product_price(0){}Sales_item(string spn, int spp) :product_name(spn), product_price(spp){}Sales_item& operator+=(const Sales_item&); private:string product_name;int product_price;friend std::istream& operator>>(std::istream&, Sales_item&);friend std::ostream& operator<<(std::ostream&, const Sales_item&); }; Sales_item& Sales_item::operator+=(const Sales_item&si) {product_price += si.product_price;return *this; }Sales_item operator+(const Sales_item&si1, const Sales_item&si2) {/*int totalprice = si1.product_price + si2.product_price;*///非成員函數(shù)不能訪問(wèn)privateSales_item si("Cakes", 0);si += si1;si += si2;return si; }std::ostream& operator<<(std::ostream&out, const Sales_item&si){out << si.product_name << ":" << si.product_price << endl;return out;//保證可以連續(xù)輸出 }std::istream& operator>>(std::istream&in, Sales_item&si){cout << "input price of "<<si.product_name << endl;in >> si.product_price;return in; }int main() {Sales_item si("Cake",15);Sales_item si2("Cake", 16);Sales_item si3("Cake", 17);Sales_item si4("Cake", 18);cout << si << endl;cin >> si;cout << si << endl;si += si2;cout << si << endl;cout << si3 + si4 << endl;system("pause");return 0; }輸出結(jié)果:
- 重載操作符的設(shè)計(jì)
不要重載具有內(nèi)置含義的操作符。賦值操作符、取地址操作符和逗號(hào)操作符對(duì)類(lèi)類(lèi)型操作數(shù)有默認(rèn)含義。如果沒(méi)有特定重載版本,編譯器就自己定義以下這些操作符。//重載操作符的一個(gè)原因就是這個(gè)操作符對(duì)類(lèi)類(lèi)型沒(méi)有操作。比如說(shuō)“+”,把兩個(gè)類(lèi)相加,加號(hào)不知道該如何操作,所以需要給這兩個(gè)類(lèi)重載加號(hào)操作符。但是有些操作符已經(jīng)有了對(duì)類(lèi)的操作,這時(shí)就不必再給這個(gè)操作符定義類(lèi)的操作了。
合成賦值操作符進(jìn)行逐個(gè)成員賦值:使用成員自己的賦值:使用成員自己的賦值操作依次對(duì)每個(gè)成員進(jìn)行賦值;默認(rèn)情況下,取地址操作符(&)和逗號(hào)操作符(,)在類(lèi)類(lèi)型對(duì)象上的執(zhí)行,與在內(nèi)置類(lèi)型對(duì)象上的執(zhí)行一樣。取地址操作符返回對(duì)象的內(nèi)存地址,逗號(hào)操作符從左至右計(jì)算每個(gè)表達(dá)式的值,并返回最右邊操作數(shù)的值;內(nèi)置邏輯與(&&)和邏輯或(||)操作符使用短路求值。如果重新定義該操作符,將失去操作符的短路求值特征。
通過(guò)為給定類(lèi)類(lèi)型的操作數(shù)重定義操作符,可以改變這些操作符的含義。重載逗號(hào)、取地址、邏輯與、邏輯或等等操作符通常不是好做法。這些操作符具有有用的內(nèi)置含義,如果我們定義了自己的版本,就不能再使用這些內(nèi)置含義。
有時(shí)我們需要定義自己的賦值運(yùn)算。這樣做時(shí),它應(yīng)表現(xiàn)得類(lèi)似于合成操作符:賦值之后,左右操作數(shù)的值應(yīng)是相同的,并且操作符應(yīng)返回對(duì)左操作數(shù)的引用。重載的賦值運(yùn)算應(yīng)在賦值的內(nèi)置含義基礎(chǔ)上進(jìn)行定制,而不是完全繞開(kāi)。
大多數(shù)操作符對(duì)類(lèi)對(duì)象沒(méi)有意義。為類(lèi)設(shè)計(jì)操作符,最好的方式是首先設(shè)計(jì)類(lèi)的公用接口。定義了接口之后,就可以考慮應(yīng)將哪些操作符定義為重載操作符。那些邏輯上可以映射到某個(gè)操作符的操作可以考慮作為候選的重載操作符。例如:相等測(cè)試操作應(yīng)使用 operator==;一般通過(guò)重載移位操作符進(jìn)行輸入和輸出;測(cè)試對(duì)象是否為空的操作可用邏輯非操作符 operator! 表示。
復(fù)合賦值操作符。如果一個(gè)類(lèi)有算術(shù)操作符或位操作符,那么,提供相應(yīng)的復(fù)合賦值操作符一般是個(gè)好的做法。例如,Sales_item 類(lèi)定義了 + 操作符,邏輯上,它也應(yīng)該定義 +=。不用說(shuō),操作符的行為應(yīng)定義為與內(nèi)置操作符一樣:復(fù)合賦值的行為應(yīng)與 + 之后接著 = 類(lèi)似。
相等和關(guān)系操作符。將要用作關(guān)聯(lián)容器鍵類(lèi)型的類(lèi)應(yīng)定義 < 操作符。關(guān)聯(lián)容器默認(rèn)使用鍵類(lèi)型的 < 操作符。即使該類(lèi)型將只存儲(chǔ)在順序容器中,類(lèi)通常也應(yīng)該定義相等(==)和小于(<)操作符,理由是許多算法假定這個(gè)操作符存在。例如 sort 算法使用 < 操作符,而 find 算法使用 == 操作符。
如果類(lèi)定義了相等操作符,它也應(yīng)該定義不等操作符 !=。類(lèi)用戶會(huì)假設(shè)如果可以進(jìn)行相等比較,則也可以進(jìn)行不等比較。同樣的規(guī)則也應(yīng)用于其他關(guān)系操作符。如果類(lèi)定義了 <,則它可能應(yīng)該定義全部的四個(gè)關(guān)系操作符(>,>=,<,<=)。
- 選擇成員或非成員實(shí)現(xiàn)
為類(lèi)設(shè)計(jì)重載操作符的時(shí)候,必須選擇是將操作符設(shè)置為類(lèi)成員還是普通非成員函數(shù)。在某些情況下,程序員沒(méi)有選擇,操作符必須是成員;在另一些情況下,有些經(jīng)驗(yàn)原則可指導(dǎo)我們做出決定。下面是一些指導(dǎo)原則,有助于決定將操作符設(shè)置為類(lèi)成員還是普通非成員函數(shù):
賦值(=)、下標(biāo)([])、調(diào)用(())和成員訪問(wèn)箭頭(->)等操作符必須定義為成員,將這些操作符定義為非成員函數(shù)將在編譯時(shí)標(biāo)記為錯(cuò)誤;像賦值一樣,復(fù)合賦值操作符通常應(yīng)定義為類(lèi)的成員,與賦值不同的是,不一定非得這樣做,如果定義非成員復(fù)合賦值操作符,不會(huì)出現(xiàn)編譯錯(cuò)誤;改變對(duì)象狀態(tài)或與給定類(lèi)型緊密聯(lián)系的其他一些操作符,如自增、自減和解引用,通常就定義為類(lèi)成員;//自增自減是為了修改自身,所以必須有對(duì)自身操作的權(quán)限,那么設(shè)為成員函數(shù)就可以修改自身的private成員,這樣設(shè)計(jì)師最好的。對(duì)稱(chēng)的操作符,如算術(shù)操作符、相等操作符、關(guān)系操作符和位操作符,最好定義為普通非成員函數(shù)。
- 輸出操作符重載
為了與 IO 標(biāo)準(zhǔn)庫(kù)一致,操作符應(yīng)接受 ostream& 作為第一個(gè)形參,對(duì)類(lèi)類(lèi)型 const 對(duì)象的引用作為第二個(gè)形參,并返回對(duì) ostream 形參的引用。重載輸出操作符一般的簡(jiǎn)單定義如下:
// general skeleton of the overloaded output operatorostream&operator <<(ostream& os, const ClassType &object){// any special logic to prepare object// actual output of membersos << // ...// return ostream objectreturn os;}第一個(gè)形參是對(duì) ostream 對(duì)象的引用,在該對(duì)象上將產(chǎn)生輸出。ostream 為非 const,因?yàn)閷?xiě)入到流會(huì)改變流的狀態(tài)。該形參是一個(gè)引用,因?yàn)椴荒軓?fù)制 ostream 對(duì)象。第二個(gè)形參一般應(yīng)是對(duì)要輸出的類(lèi)類(lèi)型的引用。該形參是一個(gè)引用以避免復(fù)制實(shí)參。它可以是 const,因?yàn)?#xff08;一般而言)輸出一個(gè)對(duì)象不應(yīng)該改變對(duì)象。使形參成為 const 引用,就可以使用同一個(gè)定義來(lái)輸出 const 和非 const 對(duì)象。返回類(lèi)型是一個(gè) ostream 引用,它的值通常是輸出操作符所操作的 ostream 對(duì)象。
ostream&operator<<(ostream& out, const Sales_item& s){out << s.isbn << "\t" << s.units_sold << "\t"<< s.revenue << "\t" << s.avg_price();return out;}輸出 Sales_item,就需要輸出它的三個(gè)數(shù)據(jù)成員以及計(jì)算得到的平均銷(xiāo)售價(jià)格,每個(gè)成員用制表符間隔。輸出值之后,該操作符返回對(duì)所寫(xiě) ostream 對(duì)象的引用。
輸出操作符格式化盡量少。關(guān)于輸出,類(lèi)設(shè)計(jì)者面臨一個(gè)重要決定:是否格式化以及進(jìn)行多少格式化。一般而言,輸出操作符應(yīng)輸出對(duì)象的內(nèi)容,進(jìn)行最小限度的格式化,它們不應(yīng)該輸出換行符。
- IO操作符必須為非成員函數(shù)
我們不能將該操作符定義為類(lèi)的成員,否則,左操作數(shù)將只能是該類(lèi)類(lèi)型的對(duì)象:
// if operator<< is a member of Sales_item Sales_item item;item << cout;//因?yàn)槌蓡T函數(shù)是類(lèi)對(duì)象發(fā)起調(diào)用,所以對(duì)象會(huì)寫(xiě)到前面。如果想要支持正常用法,則左操作數(shù)必須為 ostream 類(lèi)型。這意味著,如果該操作符是類(lèi)的成員,則它必須是 ostream 類(lèi)的成員,然而,ostream 類(lèi)是標(biāo)準(zhǔn)庫(kù)的組成部分,我們(以及任何想要定義 IO 操作符的人)是不能為標(biāo)準(zhǔn)庫(kù)中的類(lèi)增加成員的。
- 輸入操作符>>的重載
與輸出操作符類(lèi)似,輸入操作符的第一個(gè)形參是一個(gè)引用,指向它要讀的流,并且返回的也是對(duì)同一個(gè)流的引用。它的第二個(gè)形參是對(duì)要讀入的對(duì)象的非 const 引用,該形參必須為非 const,因?yàn)檩斎氩僮鞣哪康氖菍?shù)據(jù)讀到這個(gè)對(duì)象中。更重要但通常重視不夠的是,輸入和輸出操作符有如下區(qū)別:輸入操作符必須處理錯(cuò)誤和文件結(jié)束的可能性。
istream&operator>>(istream& in, Sales_item& s){double price;in >> s.isbn >> s.units_sold >> price;// check that the inputs succeededif (in)s.revenue = s.units_sold * price;elses = Sales_item(); // input failed: reset object to default statereturn in;}這個(gè)操作符從 istream 形參中讀取三個(gè)值:一個(gè) string 值,存儲(chǔ)到 isbn 成員中;一個(gè) unsigned 值,存儲(chǔ)到 Sales_item 形參的 units_sold 成員中;一個(gè) double 值,存儲(chǔ)到 Sales_item 形參的 price 成員中。假定讀取成功,操作符用 price 和 units_sold 來(lái)設(shè)置 Sales_item 對(duì)象的 revenue 成員。
檢查是否發(fā)生錯(cuò)誤:Sales_item 的輸入操作符將讀入所期望的值并檢查是否發(fā)生錯(cuò)誤??赡馨l(fā)生的錯(cuò)誤包括如下種類(lèi):任何讀操作都可能因?yàn)樘峁┑闹挡徽_而失敗。例如,讀入 isbn 之后,輸入操作符將期望下兩項(xiàng)是數(shù)值型數(shù)據(jù)。如果輸入非數(shù)值型數(shù)據(jù),這次的讀入以及流的后續(xù)使用都將失敗;任何讀入都可能碰到輸入流中的文件結(jié)束或其他一些錯(cuò)誤。
處理輸入錯(cuò)誤:如果輸入操作符檢測(cè)到輸入失敗了,則確保對(duì)象處于可用和一致的狀態(tài)是個(gè)好做法。如果對(duì)象在錯(cuò)誤發(fā)生之前已經(jīng)寫(xiě)入了部分信息,這樣做就特別重要。例如,在 Sales_item 的輸入操作符中,可能成功地讀入了一個(gè)新的 isbn,然后遇到流錯(cuò)誤。在讀入 isbn 之后發(fā)生錯(cuò)誤意味著舊對(duì)象的 units_sold 和 revenue 成員沒(méi)變,結(jié)果會(huì)將另一個(gè) isbn 與那個(gè)數(shù)據(jù)關(guān)聯(lián)。在這個(gè)操作符中,如果發(fā)生了錯(cuò)誤,就將形參恢復(fù)為空 Sales_item 對(duì)象,以避免給它一個(gè)無(wú)效狀態(tài)。用戶如果需要輸入是否成功,可以測(cè)試流。即使用戶忽略了輸入可能錯(cuò)誤,對(duì)象仍處于可用狀態(tài)——它的成員都已經(jīng)定義。類(lèi)似地,對(duì)象將不會(huì)產(chǎn)生令人誤解的結(jié)果——它的數(shù)據(jù)是內(nèi)在一致的。設(shè)計(jì)輸入操作符時(shí),如果可能,要確定錯(cuò)誤恢復(fù)措施,這很重要。//這些都是在設(shè)計(jì)一個(gè)類(lèi)時(shí)應(yīng)該考慮到的細(xì)節(jié)。
- 算術(shù)操作符和關(guān)系操作符
一般而言,將算術(shù)和關(guān)系操作符定義為非成員函數(shù),像下面給出的 Sales_item 加法操作符一樣:
// assumes that both objects refer to the same isbn Sales_itemoperator+(const Sales_item& lhs, const Sales_item& rhs){Sales_item ret(lhs); // copy lhs into a local object that we'll returnret += rhs; // add in the contents of rhsreturn ret; // return ret by value}加法操作符并不改變操作符的狀態(tài),操作符是對(duì) const 對(duì)象的引用;相反,它產(chǎn)生并返回一個(gè)新的 Sales_item 對(duì)象,該對(duì)象初始化為 lhs 的副本。我們使用 Sales_item 的復(fù)合賦值操作符來(lái)加入 rhs 的值。注意,為了與內(nèi)置操作符保持一致,加法返回一個(gè)右值,而不是一個(gè)引用。算術(shù)操作符通常產(chǎn)生一個(gè)新值,該值是兩個(gè)操作數(shù)的計(jì)算結(jié)果,它不同于任一操作數(shù)且在一個(gè)局部變量中計(jì)算,返回對(duì)那個(gè)變量的引用是一個(gè)運(yùn)行時(shí)錯(cuò)誤。既定義了算術(shù)操作符又定義了相關(guān)復(fù)合賦值操作符的類(lèi),一般應(yīng)使用復(fù)合賦值實(shí)現(xiàn)算術(shù)操作符。根據(jù)復(fù)合賦值操作符(如 +=)來(lái)實(shí)現(xiàn)算術(shù)操作符(如 +),比其他方式更簡(jiǎn)單且更有效。例如,我們的 Sales_item 操作符。如果我們調(diào)用 += 來(lái)實(shí)現(xiàn) +,則可以不必創(chuàng)建和撤銷(xiāo)一個(gè)臨時(shí)量來(lái)保存 + 的結(jié)果。
- ?相等操作符
通常,C++ 中的類(lèi)使用相等操作符表示對(duì)象是等價(jià)的。即,它們通常比較每個(gè)數(shù)據(jù)成員,如果所有對(duì)應(yīng)成員都相同,則認(rèn)為兩個(gè)對(duì)象相等。與這一設(shè)計(jì)原則一致,Sales_item 的相等操作符應(yīng)比較 isbn 以及銷(xiāo)售數(shù)據(jù):
inline booloperator==(const Sales_item &lhs, const Sales_item &rhs){// must be made a friend of Sales_itemreturn lhs.units_sold == rhs.units_sold &&lhs.revenue == rhs.revenue &&lhs.same_isbn(rhs);}inline booloperator!=(const Sales_item &lhs, const Sales_item &rhs){return !(lhs == rhs); // != defined in terms of operator==}這些函數(shù)的定義并不重要,重要的是這些函數(shù)所包含的設(shè)計(jì)原則:
如果類(lèi)定義了 == 操作符,該操作符的含義是兩個(gè)對(duì)象包含同樣的數(shù)據(jù);如果類(lèi)具有一個(gè)操作,能確定該類(lèi)型的兩個(gè)對(duì)象是否相等,通常將該函數(shù)定義為 operator== 而不是創(chuàng)造命名函數(shù)。用戶將習(xí)慣于用 == 來(lái)比較對(duì)象,而且這樣做比記住新名字更容易;如果類(lèi)定義了 operator==,它也應(yīng)該定義 operator!=。用戶會(huì)期待如果可以用某個(gè)操作符,則另一個(gè)也存在;相等和不操作符一般應(yīng)該相互聯(lián)系起來(lái)定義,讓一個(gè)操作符完成比較對(duì)象的實(shí)際工作,而另一個(gè)操作符只是調(diào)用前者。
?定義了 operator== 的類(lèi)更容易與標(biāo)準(zhǔn)庫(kù)一起使用。有些算法,如 find,默認(rèn)使用 == 操作符,如果類(lèi)定義了 ==,則這些算法可以無(wú)須任何特殊處理而用于該類(lèi)類(lèi)型。
?
轉(zhuǎn)載于:https://www.cnblogs.com/predator-wang/p/5221156.html
總結(jié)
以上是生活随笔為你收集整理的重载操作符与转换(上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: leetcode 35 Search I
- 下一篇: 3.2 矩阵和图像类型