C++過載<<和>>(C++過載輸出運算子和輸入運算子)

2020-07-16 10:04:21
在 C++ 中,左移運算子<<可以和 cout 一起用於輸出,因此也常被稱為“流插入運算子”或者“輸出運算子”。實際上,<<本來沒有這樣的功能,之所以能和 cout 一起使用,是因為被過載了。

cout 是 ostream 類的物件。ostream 類和 cout 都是在標頭檔案 <iostream> 中宣告的。ostream 類將<<過載為成員函數,而且過載了多次。為了使cout<<"Star War"能夠成立,ostream 類需要將<<進行如下過載:
ostream & ostream::operator << (const char* s)
{
    //輸出s的程式碼
    return * this;
}
為了使cout<<5;能夠成立,ostream 類還需要將<<進行如下過載:
ostream & ostream::operator << (int n)
{
    //輸出n的程式碼
    return *this;
}
過載函數的返回值型別為 ostream 的參照,並且函數返回 *this,就使得cout<<"Star War"<<5能夠成立。有了上面的過載,cout<<"Star War"<<5;就等價於:

( cout.operator<<("Star War") ).operator<<(5);

過載函數返回 *this,使得cout<<"Star War"這個表示式的值依然是 cout(說得更準確一點就是 cout 的參照,等價於 cout),所以能夠和<<5繼續進行運算。

cin 是 istream 類的物件,是在標頭檔案 <iostream> 中宣告的。istream 類將>>過載為成員函數,因此 cin 才能和>>連用以輸入資料。一般也將>>稱為“流提取運算子”或者“輸入運算子”。

例題:假定 c 是 Complex 複數類的物件,現在希望寫cout<<c;就能以 a+bi 的形式輸出 c 的值;寫cin>>c;就能從鍵盤接受 a+bi 形式的輸入,並且使得 c.real = a, c.imag = b。

顯然,要對<<>>進行過載,程式如下:
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Complex
{
    double real,imag;   
public:
    Complex( double r=0, double i=0):real(r),imag(i){ };
    friend ostream & operator<<( ostream & os,const Complex & c);
    friend istream & operator>>( istream & is,Complex & c);
};
ostream & operator<<( ostream & os,const Complex & c)
{
    os << c.real << "+" << c.imag << "i"; //以"a+bi"的形式輸出
    return os;
}
istream & operator>>( istream & is,Complex & c)
{
    string s;
    is >> s;  //將"a+bi"作為字串讀入, "a+bi" 中間不能有空格
    int pos = s.find("+",0);
    string sTmp = s.substr(0,pos); //分離出代表實部的字串
    c.real = atof(sTmp.c_str());//atof庫函數能將const char*指標指向的內容轉換成 float
    sTmp = s.substr(pos+1, s.length()-pos-2);   //分離出代表虛部的字串
    c.imag = atof(sTmp.c_str());
    return is;
}
int main()
{
    Complex c;
    int n;
    cin >> c >> n;
    cout << c << "," << n;
    return 0;
}
程式的執行結果:
13.2+133i 87
13.2+133i,87

因為沒有辦法修改 ostream 類和 istream 類,所以只能將<<>>過載為全域性函數的形式。由於這兩個函數需要存取 Complex 類的私有成員,因此在 Complex 類定義中將它們宣告為友元。

cout<<c會被解釋成operator<<(cout, c),因此編寫 operator<< 函數時,它的兩個引數就不難確定了。

第 13 行,引數 os 只能是 ostream 的參照,而不能是 ostream 物件,因為 ostream 的複製建構函式是私有的,沒有辦法生成 ostream 引數物件。operator<< 函數的返回值型別設為 ostream &,並且返回 os,就能夠實現<<的連續使用,如cout<<c<<5。在本程式中,執行第 34 行的cout<<c進入 operator<< 後,os 參照的就是 cout,因此第 34 行就能產生輸出。

用 cin 讀入複數時,對應的輸入必須是 a+bi 的格式,而且中間不能有空格,如輸入 13.2+33.4i。第 21 行的is>>s;讀入一個字串。假定輸入的格式沒有錯誤,那麼被讀入 s  的就是 a+bi 格式的字串。

讀入後需要將字串中的實部 a 和虛部 b 分離出來,分離的辦法就是找出被+隔開的兩個子串,然後將兩個字串轉換成浮點數。第 24 行呼叫了標準庫函數 atof 來將字串轉換為浮點數。該函數的原型是float atof(const char *),它在 <cstdlib> 標頭檔案中宣告。