13.7 運算子多載:輸入與輸出(延伸知識)
13.2 說過 cin >> s 是編譯錯誤——「沒人教過 cin 一個 student 長什麼樣」。現在你有工具教它了:>> 和 << 也是運算子,一樣能多載。
不過這次不能寫成成員函式。13.6 的 x < y,左邊是你的結構體,「自己」當之無愧;但 cin >> f 的左邊是 cin——型態是 istream,那是標準函式庫的東西,你塞不進去。所以這兩個多載要寫成普通函式,放在結構體外面:
#include <iostream>
using namespace std;
struct Fraction {
long long p; // 分子
long long q; // 分母
};
istream& operator >> (istream &is, Fraction &f) { // 教 cin 怎麼讀一個 Fraction
is >> f.p >> f.q;
return is; // 把 cin 還回去,>> 才能連著用
}
ostream& operator << (ostream &os, const Fraction &f) { // 教 cout 怎麼印一個 Fraction
os << f.p << '/' << f.q;
return os;
}
int main() {
Fraction a, b;
cin >> a >> b; // 像讀 int 一樣讀兩個分數
cout << a << ' ' << b << '\n'; // 像印 int 一樣印出來
return 0;
}
執行結果(輸入 1 2 3 4):
1/2 3/4
逐項拆解:
- 參數就是運算子的左右兩邊:
cin >> f對應operator >> (cin, f)——第一個參數是 stream(傳參考,因為讀取會改變 cin 的內部狀態)、第二個是你的結構體(operator >>要把讀到的值寫進去,必須傳參考;operator <<只讀不寫,加const)。 - 回傳 stream 本人:
cin >> a >> b是連鎖動作——cin >> a先執行、回傳 cin,接力棒才交得到>> b手上。忘了寫return is;,編譯器只會給個警告——但這是上冊 6.8 說的未定義行為:本機不開最佳化時可能碰巧看起來正常,開了最佳化(OJ 用的-O2)實測直接當掉。stream 一定要還回去。 - 附贈:因為回傳的是 stream,上冊 4.8 的 EOF 輸入模式
while (cin >> f)對你的型態也自動成立。
多載真正的甜頭在於格式細節全部收進函式裡。有些題目的分數輸入長成 15/2 這種樣子——把斜線當一個字元讀掉就好,主程式照樣 cin >> a,一個字都不用改:
istream& operator >> (istream &is, Fraction &f) {
char slash; // 用來接住中間的 '/'
is >> f.p >> slash >> f.q;
return is;
}
競程裡的定位:偶爾好用、不是必學。「一包資料常常整包讀寫」的場合(分數、座標、複數)最划算;只讀寫一兩次的話,成員函式或逐成員讀寫更省事。
動手試試看:解掉屋頂面積——輸入是 15/2 這種斜線格式的分數、輸出也要求最簡分數,正是本節斜線版 >> 加上 13.4 reduce() 的舞台。提示:屋頂面積怎麼用分數的加、減、乘拼出來,先畫圖想清楚;計算全程用分數,最後約分再輸出。