運(yùn)算符重載(Operator Overloading)
操作符重載的要點(diǎn)
- 操作符的通用語法
- 雙目操作符:<左操作數(shù)><操作符><右操作數(shù)>,簡單表示為,L#R。
- 單目操作符:<操作數(shù)><操作符>或<操作符><操作數(shù)>,簡單表示為,O#或#O。
- 被重載操作符的操作數(shù)中至少有一個(gè)是類類型或枚舉類型。
- 被重載操作符的操作數(shù)中至少有一個(gè)不是內(nèi)建類型,如int,char,double等及其指針或引用。
- 操作符的優(yōu)先級(jí)不會(huì)因其被重載而發(fā)生改變。
- 操作符的操作數(shù)個(gè)數(shù)不會(huì)因其被重載而發(fā)生改變。
- 除“()”之外的所有操作符都不能接受缺省參數(shù)。
- 并不是所有操作符都能被重載,如::、.*、.和?:,等等。
操作符標(biāo)記與操作符函數(shù)
- 將一個(gè)操作符標(biāo)記#應(yīng)用于一個(gè)或多個(gè)類類型的操作數(shù)時(shí),編譯器將調(diào)用與這個(gè)操作符標(biāo)記相關(guān)聯(lián)的操作符函數(shù)operator#()。
-----------+------------
操作符標(biāo)記 | 操作符函數(shù)
-----------+------------
= | operator=
+ | operator+
+= | operator+=
++ | operator++
<< | operator<<
[] | operator[]
... | ...
-----------+------------
- 操作符函數(shù)的重載定義通常包括全局函數(shù)和成員函數(shù)兩種形式。
輸入輸出操作符
- 一般而言,如果一個(gè)輸入輸出操作符#已經(jīng)按照全局函數(shù)的方式被重載定義了,那么表達(dá)式
L#R
將被編譯器解釋為如下函數(shù)調(diào)用:
operator#(L,R)
可見,按照全局函數(shù)方式被重載定義的輸入輸出操作符函數(shù),應(yīng)該有兩個(gè)參數(shù),分別是該操作符的左操作數(shù)和右操作數(shù)。
范例:io_operator.cpp - 為了能夠在操作符的全局函數(shù)重載定義中直接訪問類的私有成員,我們不妨將其聲明為該類的友元。
范例:io_friend.cpp - 友元聲明可以出現(xiàn)在一個(gè)類的私有、保護(hù)或公共部分,它允許被聲明者直接訪問該類的所有數(shù)據(jù)成員和成員函數(shù),無論其訪問控制屬性是私有的、保護(hù)的還是公共的。
范例:friend.cpp
注意:重載輸入輸出操作符,重載的對(duì)象是std::cin
和std::cout
。
雙目操作符
一般而言,如果一個(gè)雙目操作符#已經(jīng)按照成員函數(shù)的方式被重載定義了,那么表達(dá)式,??
L#R
將被編譯器解釋為如下函數(shù)調(diào)用:
L.operator#(R)
可見,按照成員函數(shù)方式被重載定義的雙目操作符函數(shù),只有一個(gè)參數(shù),即該操作符的右操作數(shù)。而該操作符的左操作數(shù)將成為此成員函數(shù)形式操作符函數(shù)的調(diào)用對(duì)象。
范例:membinary.cpp按照成員函數(shù)方式被重載定義的雙目操作符函數(shù),最終將被其左操作數(shù)所調(diào)用,且傳入其右操作數(shù)實(shí)參。因此,該操作符函數(shù)顯然應(yīng)該被定義為左操作數(shù)類型的成員函數(shù),且?guī)в幸粋€(gè)右操作數(shù)類型的形
輸出(或輸入)操作符左操作數(shù)的類型為ostream(或istream),因此我們即使能夠按照成員函數(shù)的方式為其提供重載定義,也應(yīng)該將其定義為ostream(或istream)的成員函數(shù),而我們無法為這個(gè)輸出(或輸入)流類自行添加新的成員函數(shù)。因此,我們別無選擇,只能對(duì)輸出(或輸入)操作符進(jìn)行全局重載定義。但是,我們?nèi)匀豢梢詫⑤敵?或輸入)操作符的全局重載定義聲明為被輸出(或輸入)對(duì)象類型的友元,以使它更接近于成員函數(shù)的本質(zhì)。
單目操作符
一般而言,如果一個(gè)單目操作符#已經(jīng)按照成員函數(shù)的方式被重載定義了,那么表達(dá)式:
#O
將被編譯器解釋為如下函數(shù)調(diào)用:
O.operator#()
可見,按照成員函數(shù)方式被重載定義的單目操作符函數(shù),沒有任何參數(shù)。而該操作符唯一的一個(gè)操作數(shù)將成為此成員函數(shù)形式的操作符函數(shù)的調(diào)用對(duì)象。
范例:memunary.cpp
自增自減操作符
++O ==> O.operator++()
O++ ==> O.operator++(0)
--O ==> O.operator--()
O-- ==> O.operator--(0)
注意:前綴操作符可以重復(fù)使用。
范例:memself.cpp
成員還是友元
- 一個(gè)操作符的左右操作數(shù)不一定都是相同類型的對(duì)象,這就涉及到將該操作符函數(shù)定義為誰的成員,誰的友元的問題。
例如:
cin>>a
/*操作對(duì)象*//*操作符*//*被操作對(duì)象*/
/*需要重載的對(duì)象*//*需要重載的操作符*//*被操作對(duì)象*/
一個(gè)操作符函數(shù)被聲明為哪個(gè)類的友元,取決于該函數(shù)參數(shù)對(duì)象的類型。
一個(gè)操作符函數(shù)被定義為哪個(gè)類的成員,取決于該函數(shù)調(diào)用對(duì)象的類型。
范例:friend2.cpp
類型轉(zhuǎn)換操作符與自定義類型轉(zhuǎn)換
通過類型轉(zhuǎn)換操作符可實(shí)現(xiàn)自定義類型轉(zhuǎn)換。類型轉(zhuǎn)換操作符只能被定義為源類型的成員函數(shù),而不能被定義為全局函數(shù)。當(dāng)需要進(jìn)行類型轉(zhuǎn)換時(shí)(構(gòu)造、賦值、函數(shù)調(diào)用等),編譯器將產(chǎn)生如下函數(shù)調(diào)用:
obj.operator int ();
范例:OperatorTypeConversion.cpp通過構(gòu)造函數(shù)實(shí)現(xiàn)自定義類型轉(zhuǎn)換。以源類型對(duì)象為參數(shù),通過目標(biāo)類型中特定的構(gòu)造函數(shù),創(chuàng)建一個(gè)目標(biāo)類型的對(duì)象。
范例:OperatorTypeConversion02.cpp在源類型中定義類型轉(zhuǎn)換運(yùn)算符,同時(shí)為目標(biāo)類型提供以源類型對(duì)象為參數(shù)的構(gòu)造函數(shù),不同的類型轉(zhuǎn)換方式會(huì)有各自的匹配策略:通過類型轉(zhuǎn)換運(yùn)算符完成隱式類型轉(zhuǎn)換,通過構(gòu)造函數(shù)完成靜態(tài)類型轉(zhuǎn)換。
范例:OperatorTypeConversion02.cpp為具有類型轉(zhuǎn)換性質(zhì)的構(gòu)造函數(shù)添加explicit修飾符,表明此構(gòu)造函數(shù)僅支持顯式類型轉(zhuǎn)換。通過這種機(jī)制可有效地防止誤轉(zhuǎn)換。
范例:OperatorTypeConversion03.cpp為類型轉(zhuǎn)換運(yùn)算符函數(shù)添加explicit修飾符,表明此函數(shù)僅支持顯式類型轉(zhuǎn)換。通過這種機(jī)制可有效地防止誤轉(zhuǎn)換。
范例:OperatorTypeConversion04.cpp
說明:此特性要求編譯器支持C++0X標(biāo)準(zhǔn),g++ -std=c++11 OperatorTypeConversion04.cpp
。
解引用操作符(*和->)與智能指針
函數(shù)操作符
new/delete操作符
newdel.cpp
說明:此特性要求編譯器支持C++11標(biāo)準(zhǔn),g++ -std=c++11 newdel.cpp
。