目次
はじめに
C++では、cout
(コンソール出力)や cin
(コンソール入力)だけでなく、ofstream
(ファイル出力)や stringstream
(文字列ストリーム)など、様々な種類の「ストリーム」が提供されています。これらは全て、ostream
(出力ストリーム)とistream
(入力ストリーム)という、共通の基本クラスから派生しています。
ストリーム挿入・抽出演算子 (<<
, >>
) を、この基本クラスに対してオーバーロードすることで、自作したクラスや構造体を、cout
だけでなく、ファイルや文字列といった、あらゆるストリームで統一的に、かつ直感的に扱えるようになります。
この記事では、この汎用的な入出力演算子のオーバーロード方法を解説します。
入出力演算子をオーバーロードするサンプルコード
このコードは、Vector2D
という2次元ベクトルを表す構造体を定義し、そのための operator<<
と operator>>
を実装します。そして、そのオーバーロードした演算子が、コンソール、ファイル、文字列ストリームの全てで機能することを示します。
完成コード
#include <iostream>
#include <fstream> // ファイルストリーム
#include <sstream> // 文字列ストリーム
#include <string>
using namespace std;
struct Vector2D {
double x = 0.0;
double y = 0.0;
};
// --- 1. 出力演算子(<<)のオーバーロード ---
// 第1引数で、特定のcoutではなく、汎用的なostream&を受け取る
ostream& operator<<(ostream& os, const Vector2D& v) {
os << v.x << " " << v.y; // 例: "1.5 3.2" のように出力
return os;
}
// --- 2. 入力演算子(>>)のオーバーロード ---
// 第1引数で、特定のcinではなく、汎用的なistream&を受け取る
istream& operator>>(istream& is, Vector2D& v) {
is >> v.x >> v.y;
return is;
}
int main() {
Vector2D p1 = {1.5, 3.2};
Vector2D p2;
// --- a. コンソールでの利用 (cout, cin) ---
cout << "コンソール出力: " << p1 << endl;
// --- b. 文字列ストリームでの利用 (stringstream) ---
stringstream ss;
ss << p1; // Vector2Dオブジェクトを文字列ストリームに出力
ss >> p2; // 文字列ストリームからVector2Dオブジェクトに入力
cout << "文字列ストリーム経由: " << p2 << endl;
// --- c. ファイルストリームでの利用 (fstream) ---
ofstream ofs("vector_data.txt");
ofs << p1; // ファイルに書き出し
ofs.close();
ifstream ifs("vector_data.txt");
ifs >> p2; // ファイルから読み込み
ifs.close();
cout << "ファイルストリーム経由: " << p2 << endl;
return 0;
}
コードの解説
ostream& operator<<(ostream& os, const Vector2D& v)
ostream& os
: この関数の第1引数は、cout
に限定されません。ostream
クラスから派生したあらゆる出力ストリームオブジェクトへの参照を受け取ることができます。cout
もofstream
もstringstream
も、全てこのostream
の一種です。return os;
:cout << a << b;
のように出力を連鎖させるために、受け取ったストリームオブジェクトへの参照をそのまま返します。
istream& operator>>(istream& is, Vector2D& v)
istream& is
: 同様に、この関数の第1引数は、cin
だけでなく、ifstream
やstringstream
など、istream
クラスから派生したあらゆる入力ストリームオブジェクトへの参照を受け取ることができます。
汎用性の実証
main
関数では、一度定義した operator<<
と operator>>
が、
cout << p1
: コンソール出力ss << p1
: 文字列ストリームへの出力ofs << p1
: ファイルストリームへの出力 という3つの異なる場面で、全く同じように機能していることが分かります。入力も同様です。
まとめ
今回は、C++の入出力ストリームの基本クラスである ostream
/ istream
に対して演算子をオーバーロードする方法を解説しました。
cout
/cin
ではなく、ostream&
/istream&
を引数に取ることで、関数は汎用的になる。- 一度このオーバーロードを定義すれば、自作の型が、コンソールだけでなく、ファイルや文字列など、C++の全ての標準ストリームで統一的に扱えるようになる。
これが、C++のストリームライブラリの強力な特徴であり、型安全で再利用性の高いコードを書くための基本原則です。