継承クラスを出力演算子のオーバーロードで出力したい場合、operator<<自体を仮想関数にはできないため、仮想メンバ関数を中継に使う方法が一般的である。
operator<<は通常、非メンバ関数として定義する。
しかし、非メンバ関数は仮想関数にできない。
そのため、基底クラスに仮想のprint()のようなメンバ関数を用意し、operator<<の中からその関数を呼ぶ。
例
class Base
{
public:
virtual void print(std::ostream& out) const
{
out << "Base";
}
friend std::ostream& operator<<(std::ostream& out, const Base& b)
{
b.print(out);
return out;
}
};
class Derived : public Base
{
public:
void print(std::ostream& out) const override
{
out << "Derived";
}
};この場合、std::cout << derived;だけでなく、Base&やBase*を通して扱っている場合でも、print()が仮想呼び出しされることで、実際の型に応じた出力が行われる。
基底クラスの出力を使い回す
派生クラスで基底クラス部分の出力も使いたい場合は、基底クラスのprint()を呼んでから派生クラス固有の情報を追加できる。
void print(std::ostream& out) const override
{
Base::print(out);
out << " Derived";
}注意
operator<<自体は仮想関数にできない- 多態的な出力をしたい場合は、仮想メンバ関数を1つ中継に使う
- 継承階層で出力を拡張しやすい