1. 程式人生 > >C++流插入(輸出)和流提取(輸入)運算子的過載

C++流插入(輸出)和流提取(輸入)運算子的過載

參考:coursera C++程式設計

目錄

流插入運算子過載

問題

1. cout是什麼?
2. 為什麼 << 可以用在cout
3. 為什麼 cout << 5 << "this"能夠成立

  • 首先,coutiostream中定義的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;
}

在本例中,realimag為私有成員變數,因此只能用友元函式過載。

流提取運算子過載

在上例中,如何實現以指定形式(13.2+133i)讀取從鍵盤中輸入的資料呢?
原理是相似的,但操作有點麻煩。
需要以字串形式讀取資料,再將realimag分開並轉換為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;
}

總結

  • 運算子過載本質上都是對過載函式的呼叫,過載函式可分為成員函式友元函式全域性函式
  • 由於流提取和流插入運算子的過載函式的返回值必須是istreamostream類的引用,而這兩個類已經在標頭檔案中寫好,不便更改,所以用全域性或友元函式過載。
  • 當這兩個運算子的作用物件(在本例中為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;
}

執行成功!
這麼做只是為了驗證我的想法,僅僅為了學習,實際應用中非常不建議這麼做