【C++】自作クラスを入出力ストリーム (ostream/istream) に対応させる方法

目次

はじめに

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クラスから派生したあらゆる出力ストリームオブジェクトへの参照を受け取ることができます。coutofstreamstringstream も、全てこの ostream の一種です。
  • return os;: cout << a << b; のように出力を連鎖させるために、受け取ったストリームオブジェクトへの参照をそのまま返します。

istream& operator>>(istream& is, Vector2D& v)

  • istream& is: 同様に、この関数の第1引数は、cinだけでなく、ifstreamstringstreamなど、istreamクラスから派生したあらゆる入力ストリームオブジェクトへの参照を受け取ることができます。

汎用性の実証

main関数では、一度定義した operator<<operator>> が、

  • cout << p1: コンソール出力
  • ss << p1: 文字列ストリームへの出力
  • ofs << p1: ファイルストリームへの出力 という3つの異なる場面で、全く同じように機能していることが分かります。入力も同様です。

まとめ

今回は、C++の入出力ストリームの基本クラスである ostream / istream に対して演算子をオーバーロードする方法を解説しました。

  • cout/cin ではなく、ostream& / istream& を引数に取ることで、関数は汎用的になる。
  • 一度このオーバーロードを定義すれば、自作の型が、コンソールだけでなく、ファイルや文字列など、C++の全ての標準ストリームで統一的に扱えるようになる。

これが、C++のストリームライブラリの強力な特徴であり、型安全で再利用性の高いコードを書くための基本原則です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次