C++ Primer 學習筆記_59_重載操作符與轉換

來源:互聯網
上載者:User

重載操作符與轉換--輸入/輸出、算術/關係操作符



   支援I/O操作的類所提供的I/O操作介面,一般應該與標準庫iostream為內建類型定義的介面相同,因此,許多類都需要重載輸入和輸出操作符。

一、輸出操作符<<的重載

   為了與IO標準庫一致,操作符應接受ostream&作為第一個形參,對類類型const對象的引用作為第二個形參,並返回ostream形參的引用!

ostream &operator<<(ostream &os,const ClassType &object){    os << //....    return os;}

1、Sales_item輸出操作符

ostream &operator<<(ostream &out,const Sales_item &object){    out << object.isbn << '\t' << object.units_sold << '\t'        << object.revenue << '\t' << object.avg_price();    return out;}

2、輸出操作符通常所做格式化應盡量少

    一般而言,輸出操作符應輸出對象的內容,進行最小限度的格式化,它們不應該輸出分行符號!盡量減少操作符的格式化,可以讓使用者自己控制輸出細節。

    Sales_item item("C++ Primer");    cout << item << endl;//使用者自己控制輸出分行符號

3、IO操作符必須為非成員函數

    我們不能將該操作符定義為類的成員,否則,左操作符只能是該類型的對象:

ostream &Sales_item::operator<<(ostream &out){    out << isbn << '\t' << units_sold << '\t'        << revenue << '\t' << avg_price();    return out;}

//測試    Sales_item item("C++ Primer");    //這個用法與正常使用方式恰好相反    item << cout << endl;    //OR    item.operator<<(cout);    //Error    cout << item << endl;

    如果想要支援正常用法,則左運算元必須為ostream類型。這意味著,如果該操作符是類的成員,則它必須是ostream類的成員,然而,ostream類是標準庫的組成部分,我們(以及任何想要定義IO操作符的人)是不能為標準庫中的類增加成員的。

    由於IO操作符通常對非公用資料成員進行讀寫,因此,類通常將IO操作符設為友元。

//P437 習題14.7class CheckoutRecord{    friend ostream &operator<<(ostream &os,const CheckoutRecord &object);public:    typedef unsigned Date;    //...private:    double book_id;    string title;    Date date_borrowed;    Date date_due;    pair<string,string> borrower;    vector< pair<string,string> * > wait_list;};ostream &operator<<(ostream &os,const CheckoutRecord &obj){    os << obj.book_id << ": " << obj.title << '\t' << obj.date_borrowed       << '\t' << obj.date_due << '\t' << obj.borrower.first << ' '       << obj.borrower.second << endl;    os << "Wait_list:" << endl;    for (vector< pair<string,string> * >::const_iterator iter = obj.wait_list.begin();            iter != obj.wait_list.end(); ++iter)    {        os << (*iter) -> first << '\t' << (*iter) -> second << endl;    }}

二、輸入操作符>>的重載

    與輸出操作符類似,輸入操作符的第一個形參是一個引用,指向它要讀的流,並且返回的也是對同一個流的引用。它的第二個形參是對要讀入的對象的非const引用,該形參必須為非const,因為輸入操作符的目的是將資料讀到這個對象中。

     輸入操作符必須處理錯誤和檔案結束的可能性!


1、Sales_item的輸入操作符

istream &operator>>(istream &in,Sales_item &s){    double price;    in >> s.isbn >> s.units_sold >> price;    if (in)    {        s.revenue = price * s.units_sold;    }    else    {        //如果讀入失敗,則將對象重新設定成為預設狀態        s = Sales_item();    }    return in;}

2、輸入期間的錯誤

   可能發生的錯誤包括:

    1)任何讀操作都可能因為提供的值不正確而失敗。例如,讀入isbn之後,輸入操作符將期望下兩項是數值型資料。如果輸入非數值型資料,這次的讀入以及流的後續使用都將失敗。

    2)任何讀入都可能碰到輸入資料流中的檔案結束或其他一些錯誤。

  但是我們無需檢查每次讀入,只在使用讀入資料之前檢查一次即可。

    if (in)    {        s.revenue = price * s.units_sold;    }    else    {        s = Sales_item();    }

如果一旦出現了錯誤,我們不用關心是哪個輸入失敗了,相反,我們將整個對象複位!



3、處理輸入錯誤

   如果輸入操作符檢測到輸入失敗了,則確保對象處於可用和一致狀態是個好做法!如果對象在發生錯誤之前已經寫入了部分資訊,這樣做就特別重要!

   例如,在Sales_item的輸入操作符中,可能成功地讀入了一個新的isbn,然後遇到流錯誤。在讀入isbn之後發生錯誤意味著舊對象的units_sold和 revenue成員沒變,結果會將另一個isbn與那個資料關聯(悲劇了...。因此,將形參恢複為空白Sales_item對象,可以避免給他一個無效的狀態!

【最佳實務】

   設計輸入操作符時,如果可能,要確定錯誤恢複措施,這很重要!


4、指出錯誤

   除了處理可能發生的任何錯誤之外,輸入操作符還可能需要設定輸入形參的條件狀態。

   有些輸入操作符的確需要進行附加檢查。例如,我們的輸入操作符可以檢查讀到的 isbn格式是否恰當。也許我們已成功讀取了資料,但這些資料不能恰當解釋為ISBN,在這種情況下,儘管從技術上說實際的IO是成功的,但輸入操作符仍可能需要設定條件狀態以指出失敗。通常輸入操作符僅需設定failbit。設定 eofbit意思是檔案耗盡,設定badbit可以指出流被破壞,這些錯誤最好留給 IO標準庫自己來指出

//P439 習題14.11class CheckoutRecord{    friend istream &operator>>(istream &in,CheckoutRecord &object);public:    typedef unsigned Date;    //...private:    double book_id;    string title;    Date date_borrowed;    Date date_due;    pair<string,string> borrower;    vector< pair<string,string> * > wait_list;};istream &operator>>(istream &in,CheckoutRecord &obj){    in >> obj.book_id >> obj.title >> obj.date_borrowed >> obj.date_due;    in >> obj.borrower.first >> obj.borrower.second;    if (!in)    {        obj = CheckoutRecord();        return in;    }    obj.wait_list.clear();    while (in)    {        pair<string,string> *p = new pair<string,string>;        in >> p -> first >> p -> second;        if (in)        {            obj.wait_list.push_back(p);            delete p;        }    }    return in;}

三、算術運算子

   一般而言,將算術和關係操作符定義為非成員函數:

Sales_item operator+(const Sales_item &lhs,const Sales_item &rhs){    Sales_item ret(lhs);    //使用Sales_item的複合複製操作符來加入rhs的值    ret += rhs;    return ret;}

加法操作符並不改變運算元的狀態,運算元是對const對象的引用。

【最佳實務】

   為了與內建操作符保持一致,加法返回一個右值,而不是一個引用!

   既定義了算術操作符又定義了先關複合賦值操作符的類,一般應使用複合賦值實現算術操作符。

//P440 習題14.12Sales_item operator+(const Sales_item &lhs,const Sales_item &rhs){    Sales_item tmp;    tmp.units_sold = lhs.units_sold + rhs.units_sold;    tmp.revenue = lhs.revenue + rhs.revenue;    return tmp;}Sales_item& Sales_item::operator+=(const Sales_item& rhs){    *this = *this + rhs;    return *this;}

四、關係運算子

1、相等運算子

   如果所有對應成員都相等,則認為兩個對象相等。

inlinebool operator==(const Sales_item &lhs,const Sales_item &rhs){    return lhs.revenue == rhs.revenue && lhs.units_sold == rhs.units_sold &&           lhs.same_isbn(rhs);}inlinebool operator!=(const Sales_item &lhs,const Sales_item &rhs){    return !(lhs == rhs);}

   1)如果類定義了==操作符,該操作符的含義是兩個對象包含同樣的資料。

   2)如果類具有一個操作,能確定該類型的兩個對象是否相等,通常將該函數定義為 operator==而不是創造命名函數。使用者將習慣於用==來比較對象,而且這樣做比記住新名字更容易

   3)如果類定義了operator==,它也應該定義operator!=。使用者會期待如果可以用某個操作符,則另一個也存在。

   4)相等和不操作符一般應該相互聯絡起來定義,讓一個操作符完成比較對象的實際工作,而另一個操作符只是調用前者

定義了operator==的類更容易與標準庫一起使用。有些演算法,如find,預設使用==操作符,如果類定義了==,則這些演算法可以無需任何特殊處理而用於該類類型!


2、關係操作符

   定義了相等操作符的類一般也具有關係操作符。尤其是,因為關聯容器和某些演算法使用小於操作符(<),所以定義了operator<可能相當有用。

   如果因為<的邏輯定義與==的邏輯定義不一致,所以這樣的話,不定義<會更好。

【注釋】

   關聯容器以及某些演算法,預設使用<操作符(此處本人認為譯者翻譯有誤,原文:...usethe < operator bydefult...,譯者翻譯為:使用預設<操作符,但本人認為預設使用更為恰當!)。一般而言,關係操作符,諸如相等操作符,應定義為非成員函數(“對稱”操作符)。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.