ストリーム演算子
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 43/104。
ストリーム挿入(<<)演算子と抽出(>>)演算子を使用すると、自作のクラスを std::cout や std::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に読み込むチャレンジ
簡単ストリーム演算子のオーバーロードを通じて、std::cout や std::cin でシームレスに使用できる Temperature クラスを構築しましょう。これは、温度を読みやすい形式で表示し、入力から自然に読み取りたいという実用的なシナリオです。
コードを整理するために、2つのファイルを作成します。
Temperature.h: 摂氏の値(double型)と単位ラベル(char型、摂氏の場合は'C'、華氏の場合は'F')を保持するTemperatureクラスを定義します。クラスには以下を含める必要があります。- 温度の値と単位のためのプライベートメンバ
- 0.0 摂氏に初期化するデフォルトコンストラクタ
- 値と単位を受け取る引数付きコンストラクタ
- ゲッター
getValue()およびgetUnit()(どちらも const) - ストリーム挿入(
<<)および抽出(>>)演算子のフレンド宣言
ストリーム演算子を非メンバ関数として実装します。
- 挿入演算子は、温度を
VALUE UNITの形式(例:25.5 Cや77.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::fixed と std::setprecision(1) を使用してください。ヘッダーファイルにはヘッダーガードを忘れずに入れてください。
チートシート
ストリーム挿入(<<)および抽出(>>)演算子を使用すると、カスタムクラスを std::cout や std::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;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス