重載操作符(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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章