Menu
Coddy logo textTech

ストリーム演算子

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 43/104。

ストリーム挿入(<<)演算子と抽出(>>)演算子を使用すると、自作のクラスを std::coutstd::cin と共に使用できるようになります。これまでに説明した演算子とは異なり、これらは非メンバ関数として実装する必要があります。なぜなら、左側のオペランドが自作のクラスではなく、ストリームだからです。

class Point {
    int x, y;
    
public:
    Point(int x, int y) : x(x), y(y) {}
    
    // プライベートメンバにアクセスするためにfriendとして宣言します
    friend std::ostream& operator<<(std::ostream& os, const Point& p);
    friend std::istream& operator>>(std::istream& is, Point& p);
};

std::ostream& operator<<(std::ostream& os, const Point& p) {
    os << "(" << p.x << ", " << p.y << ")";
    return os;
}

std::istream& operator>>(std::istream& is, Point& p) {
    is >> p.x >> p.y;
    return is;
}

両方の演算子はストリームへの参照を返すため、std::cout << p1 << p2 のような連鎖的な記述が可能です。挿入演算子はデータを読み取るだけなのでオブジェクトを const 参照で受け取りますが、抽出演算子はオブジェクトを変更するため、非const参照を受け取ります。

これで、Pointをストリームで自然に使用できるようになります:

Point p(3, 4);
std::cout << "Location: " << p << std::endl;    // 出力: Location: (3, 4)

Point p2(0, 0);
std::cin >> p2;    // 2つの整数をp2に読み込む
challenge icon

チャレンジ

簡単

ストリーム演算子のオーバーロードを通じて、std::coutstd::cin でシームレスに使用できる Temperature クラスを構築しましょう。これは、温度を読みやすい形式で表示し、入力から自然に読み取りたいという実用的なシナリオです。

コードを整理するために、2つのファイルを作成します。

  • Temperature.h: 摂氏の値(double 型)と単位ラベル(char 型、摂氏の場合は 'C'、華氏の場合は 'F')を保持する Temperature クラスを定義します。クラスには以下を含める必要があります。
    • 温度の値と単位のためのプライベートメンバ
    • 0.0 摂氏に初期化するデフォルトコンストラクタ
    • 値と単位を受け取る引数付きコンストラクタ
    • ゲッター getValue() および getUnit()(どちらも const)
    • ストリーム挿入(<<)および抽出(>>)演算子のフレンド宣言

    ストリーム演算子を非メンバ関数として実装します。

    • 挿入演算子は、温度を VALUE UNIT の形式(例:25.5 C77.9 F)で出力する必要があります。値には小数点以下1桁を使用してください。
    • 抽出演算子は、ストリームから値と単位文字を読み取り、それらを Temperature オブジェクトに格納する必要があります。

    どちらの演算子も、連鎖(チェイニング)を可能にするためにストリームへの参照を返す必要があります。

  • main.cpp: 入力から2つの温度を読み取ります。各温度は、value unit の形式(例:25.5 C)で別々の行に提供されます。

    抽出演算子を使用して std::cin から読み取り、2つの Temperature オブジェクトを作成します。次に、挿入演算子を使用して、以下の形式で出力します。

    Temperature 1: <temp1>
    Temperature 2: <temp2>

    例えば、入力が以下の場合:

    25.5 C
    98.6 F

    出力は以下のようになります:

    Temperature 1: 25.5 C
    Temperature 2: 98.6 F

温度の値を正確に小数点以下1桁でフォーマットするために、<iomanip>std::fixedstd::setprecision(1) を使用してください。ヘッダーファイルにはヘッダーガードを忘れずに入れてください。

チートシート

ストリーム挿入(<<)および抽出(>>)演算子を使用すると、カスタムクラスを std::coutstd::cin と連携させることができます。これらの演算子は、左オペランドがクラスではなくストリームオブジェクトであるため、非メンバ関数として実装する必要があります。

基本構文

class Point {
    int x, y;
    
public:
    Point(int x, int y) : x(x), y(y) {}
    
    // Declare as friend to access private members
    friend std::ostream& operator<<(std::ostream& os, const Point& p);
    friend std::istream& operator>>(std::istream& is, Point& p);
};

std::ostream& operator<<(std::ostream& os, const Point& p) {
    os << "(" << p.x << ", " << p.y << ")";
    return os;
}

std::istream& operator>>(std::istream& is, Point& p) {
    is >> p.x >> p.y;
    return is;
}

重要なポイント

  • 連鎖(例:std::cout << p1 << p2)を可能にするため、両方の演算子はストリームへの参照を返します。
  • 挿入演算子(<<)は、データを読み取るだけなので、オブジェクトを const 参照で受け取ります。
  • 抽出演算子(>>)は、オブジェクトを変更するため、非 const 参照を受け取ります。
  • これらの非メンバ関数がプライベートメンバにアクセスできるようにするには、friend 宣言を使用します。

使用例

Point p(3, 4);
std::cout << "Location: " << p << std::endl;    // Output: Location: (3, 4)

Point p2(0, 0);
std::cin >> p2;    // Read two integers into p2

自分で試してみよう

#include <iostream>
#include "Temperature.h"

int main() {
    // TODO: 2つの Temperature オブジェクトを作成する
    
    // TODO: 抽出演算子 (>>) を使用して std::cin から2つの温度を読み込む
    
    // TODO: 挿入演算子 (<<) を使用して温度を出力する
    // 形式:
    // Temperature 1: <temp1>
    // Temperature 2: <temp2>
    
    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン