C++流插入(輸出)和流提取(輸入)運算子的過載
參考:coursera C++程式設計
目錄
流插入運算子過載
問題
1. cout
是什麼?
2. 為什麼 <<
可以用在cout
上
3. 為什麼 cout << 5 << "this"
能夠成立
- 首先,
cout
是iostream
中定義的ostream
類的物件 >>
能用在cout
上是因為,在iostream
裡對<<
進行了過載
cout << 5
cout.operator<<(5)
cout << "this"
相當於執行函式cout.operator<<("this")
那麼如何過載才能使得cout << 5 << "this"
成立?
答案就是:返回值為cout型別
ostream& ostream::operator<<(int n)
{
//輸出n的程式碼
return *this;
}
ostream& ostream::operator<<(const char* s)
{
//輸出s的程式碼
return *this;
}
因此,cout << 5 << "this"
實質上是執行函式:
cout.operator<<(5).operator<<("this");
自定義過載實現
如果在程式中希望對<<
運算子進行過載,使其能夠輸出自定義的資料,如何實現呢?
由於ostream
型別已經在iostream
中實現,所以不能作為ostream
類的成員函式過載,只能作為全域性函式或友元函式過載。
例:
全域性函式實現:
class CStudent{
public:
int age;
};
int main()
{
CStudent s;
s.age = 5;
cout << s << "Hello";
return 0;
}
假設輸出為5Hello
,<<
過載函式怎麼實現?
ostream & operator<<(ostream & o, const CStudent & s) {//此處為了節省執行時間,使用了CStudent &
o << s.age;
return o;
}
友元函式實現
假定c是complex複數類的物件,現在希望寫cout << c;
就能以a+bi
的形式輸出c的值,寫cin >> c;
就能從鍵盤接受a+bi
形式的輸入,並且使c.real = a, c.imag = b
主程式:
int main() {
Complex c;
int n;
cin >> c >> n;
cout << c << "," << n;
return 0;
}
程式執行結果可以如下:
輸入:13.2+133i 87
輸出:13.2+133i,87
#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;
}
在本例中,real
和imag
為私有成員變數,因此只能用友元函式過載。
流提取運算子過載
在上例中,如何實現以指定形式(13.2+133i
)讀取從鍵盤中輸入的資料呢?
原理是相似的,但操作有點麻煩。
需要以字串形式讀取資料,再將real
和imag
分開並轉換為double
格式。
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;
}
總結
- 運算子過載本質上都是對過載函式的呼叫,過載函式可分為成員函式,友元函式,全域性函式。
- 由於流提取和流插入運算子的過載函式的返回值必須是
istream
或ostream
類的引用,而這兩個類已經在標頭檔案中寫好,不便更改,所以用全域性或友元函式過載。 - 當這兩個運算子的作用物件(在本例中為
Complex
類)為自定義時,可以用全域性函式、complex
類的友元函式過載。
又有一個問題
寫到這裡我產生了一個疑問,那能不能用Complex
的成員函式過載呢?
於是,我把<<
過載函式的friend
去掉了,改成:
ostream & operator<<( ostream & os);
又把定義改成:
ostream & Complex::operator<<( ostream & os)
{
os << real << "+" << imag << "i"; //以"a+bi"的形式輸出
return os;
}
結果報錯了,查了之後發現運算子過載函式對引數的順序是有要求的,二元運算子的過載函式的引數需要與呼叫時保持一致。成員函式第一個引數預設為*this
,這就意味著呼叫時運算子左邊必須為該類的物件,右邊為ostream
物件。因此稍微修改主函式程式碼:
int main() {
Complex c;
int n;
cin >> c >> n;
//cout << c << "," << n;
c << cout;//注意,c和cout的順序變了
return 0;
}
執行成功!
這麼做只是為了驗證我的想法,僅僅為了學習,實際應用中非常不建議這麼做