重載操作符(2)
支持I/O操作的類所提供的I/O操作接口,一般應該與標準庫iostream爲內置類型定義的接口相同。因此,許多類都需要重載輸入和輸出操作符。
輸出操作符<<的重載
爲了與IO標準庫一致,操作符應接受ostream&作爲第一個形參,對類類型const對象的引用作爲第二個形參,並返回對ostream形參的引用。
重載輸出操作符一般的簡單定義如下:
// general skeleton of the overloaded ouput operator
Ostream& operator <<(ostream& os, const ClassType &object)
{
// any special logic to prepare object
// actual ouput of members
os < …
// return ostream object
return os;
}
第一個形參是對ostream對象的引用,在該對象上產生輸出,ostream爲非const,因爲下入到流會改變流的狀態。該形參是一個引用,因爲不能複製ostream對象。
第二個對象一般應是對要輸出的類類型的引用。該形參是一個引用以避免複製實參。它可以是const,因爲輸出一個對象不應該改變該對象。
返回類型是一個ostream引用,它的值通常是輸出操作符所操作的ostream對象。
輸出操作符通常所做格式化應儘量少。
關於輸出,類設計者面臨着一個重要決定:是否格式化以及進行多少格式化。
一般而言,輸出操作符應輸出對象的內容,進行最小限度的格式化,他們不應該輸出換行符。
用於內置類型的輸出操作符所作的格式化很少,並且不輸出換行符。通過限制輸出操作符只輸出對象的內容,如果需要執行任意額外的格式化,我們讓用戶決定該如何處理。尤其是,輸出操作符不應該輸出換行符。儘量減少操作符所作的格式化,讓用戶自己控制輸出細節。
IO操作符必須爲非成員函數
當定義符合標準庫iostream規範的輸入或輸出操作符的時候,必須使它成爲非成員操作符。
我們不能將該操作符定義爲類的成員,否則,左操作數將只能是該類類型的對象。
// if operator < Sales_item item;
item < 這個用法與爲其他類型定義的輸出操作符的正常使用方式相反。如果想要支持正常的用法,則左操作數必須爲ostream類型。如果該操作符是類的成員,則它必須是ostream類的成員,然而ostream類是標準庫的組成部分,我們是不能爲標準庫的類增加成員的。
如果想要使用重載操作符爲該類型提供IO操作,就必須將他們定義爲非成員函數。IO操作符通常對非公用數據成員進行讀寫,因此,類通常將IO操作符設爲友元。
輸入操作符>>的重載
與輸出操作符類似:輸入操作符的第一個形參是一個引用,指向它要讀的流,並且返回的也是對同一個流的引用。它的第二個形參是對要讀入的對象的非const引用,該形參必須爲非const,因爲輸入操作符的目的是將數據讀到這個對象中。
ostream& operator >>(ostream& os, ClassType &object)
需要注意的是:輸入和輸出操作符有如下區別,輸入操作符必須處理錯誤和文件結束的可能性。
如何處理輸入錯誤
如果輸入操作符檢測到輸入失敗了,則確保對象處於可用和一致的狀態是個好做法。如果對象在錯誤發生之前已經寫入了部分欣喜,這樣做就特別重要。
如果發生了錯誤,就將形參恢復爲空對象,以避免給它一個無效的狀態。用戶如果需要知道輸入是否成功,可以測試流。即使用戶忽略了輸入可能錯誤,對象仍處於可用狀態——他的成員已經定義。
設計輸入操作符時,如果可能,要確定錯誤恢復措施,這很重要。
指出錯誤
除了處理可能發生的任何錯誤之外,輸入操作符還可能需要設置輸入形參的條件狀態。我們的輸入操作符相當簡單——我們只關心讀入期間可能發生的錯誤。
算術操作符和關係操作符
一般而言,將算術和關係操作符定義爲非成員函數。爲了與內置操作符保持一致,加法返回一個右值,而不是一個引用
例:
// assumes that both objects refer to the same isbn
Sales_item operator +(const Sales_item& lhs, const Sales_item& rhs)
{
Sales_item ret(lhs);
ret += rhs;
return ret; // ret 因該理解爲左值還是右值呢?概念有所混淆 我覺得返回的是左值
}
算術操作符通常產生一個新值,該值是兩個操作數的計算結果,它不同於任一操作數且在一個局部變量中計算,返回對那個變量的引用是一個運行時的錯誤。
既定義了算術操作符又定義了相關複合賦值操作符的類,一般應使用複合賦值實現算術操作符。
賦值操作符
類賦值操作符接受類類型的形參,通常,該形參是對類類型的const引用,但也可以是類類型或對類類型的非const 引用。如果沒有定義這個操作符,編譯器就會合成它。類賦值操作符必須是類的成員,以便編譯器可以知道是否需要合成一個。
賦值操作符可以重載。無論形參爲何種類型,賦值操作符必須定義爲成員函數。
賦值必須返回對*this的引用。
因爲賦值返回的是一個引用,就不需要創建和撤銷結果的臨時副本。返回值通常是左操作數的引用。
注意:一般而言,賦值操作符與複合賦值操作符應返回左操作數的引用。
下標操作符
下標操作符必須定義爲類成員函數。
提供讀寫訪問
定義下標操作符比較複雜的地方在於,它在用作賦值的左右操作數時都應該能表現正常,下標操作符出現在左邊,必須生成左值,可以指定引用作爲返回類型而得到左值。只要下標操作符返回引用,就可用作賦值的任意一方。
類定義下標操作符的時候,一般需要定義兩個版本:一個爲非const成員並返回引用,另一個爲const成員並返回const引用。
自增操作符和自減操作符
定義自增/自減操作符
C++語言不要求自增操作符或自減操作符一定作爲類的成員,但是,因爲這些操作符改變操作對象的狀態。但是,因爲這些操作符改變操作對象的狀態,所以更傾向於將他們作爲成員函數。
定義前自減/前自增操作符
class CheckedPtr
{
public:
CheckedPtr& operator++();
CheckedPtr& operator—();
};
爲了與內置類型一致,前綴式操作符應返回被增量或減量對象的引用。
區別操作符的前綴和後綴形式
前綴式和後綴式存在一個問題:它們的形參數目和類型相同
爲了解決這個問題,後綴式操作符函數接受一個額外的int型形參。使用後綴式操作符時,編譯器提供0座位這個形參的實參。
定義後綴式操作符
class CheckedPtr
{
public:
CheckedPtr operator ++ (int);
CheckedPtr operator – (int);
};
爲了與內置操作符一致,後綴式操作符應返回舊值(尚未自增或自減的值),並且應作爲值返回,而不是返回應用。
一般而言,最好前綴式和後綴式都定義。只定義前綴式或只定義後綴式的類,將會讓習慣於使用兩種形式的用戶感到奇怪。
調用操作符和函數對象
可以爲類類型的對象重載函數調用操作符。一般爲表示操作的類重載調用操作符。
例如,可以定義名爲absInt的結構,該結構將int類型的值轉換爲絕對值得操作:
class absInt
{
int operator()(int val)
{
Return val <0 ? –val: val;
}
};
這個結構很簡單,它定義了一個操作,函數調用操作符,該操作符有一個形參並返回形參的絕對值。
通過類類型的對象提供一個實參表而使用調用操作符,所用的方式看起來像一個函數調用。
函數調用操作符必須聲明爲成員函數,一個類可以定義函數調用操作符的多個版本,由形參的數目或類型加以區別。
定義了調用操作符的類,其對象常稱爲函數對象,即它們是行爲類似函數的對象。
本文轉自
http://blog.csdn.net/sandyqy/archive/2007/10/07/1813649.aspx
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.