18.11 Printing inherited classes using operator<<


https://www.learncpp.com/cpp-tutorial/printing-inherited-classes-using-operator/
virtualfunctionを使用した以下のプログラムを見てみましょう
#include <iostream>

class Base
{
public:
	virtual void print() const { std::cout << "Base";  }
};

class Derived : public Base
{
public:
	void print() const override { std::cout << "Derived"; }
};

int main()
{
	Derived d{};
	Base& b{ d };
	b.print(); // will call Derived::print()

	return 0;
}
b.print呼び出しDerived::print()について説明します.
std::coutと結びつけたいのですが、現在の形式ではきれいに使えません.
#include <iostream>

int main()
{
	Derived d{};
	Base& b{ d };

	std::cout << "b is a ";
	b.print(); // messy, we have to break our print statement to call this function
	std::cout << '\n';

	return 0;
}
b.print()はstd::coutが存在します.上のように書くべきです.
理想的には、以下のように簡潔明瞭に書く
std::cout << "b is a " << b << '\n'; // much better

The challenges with operator<<


オペレータ<<通常の方法で再ロードしましょう
#include <iostream>

class Base
{
public:
	virtual void print() const { std::cout << "Base"; }

	friend std::ostream& operator<<(std::ostream& out, const Base& b)
	{
		out << "Base";
		return out;
	}
};

class Derived : public Base
{
public:
	void print() const override { std::cout << "Derived"; }

	friend std::ostream& operator<<(std::ostream& out, const Derived& d)
	{
		out << "Derived";
		return out;
	}
};

int main()
{
	Base b{};
	std::cout << b << '\n';

	Derived d{};
	std::cout << d << '\n';

	return 0;
}
上のプログラムを実行し、次のように出力します.
Base
Derived
BaseRefに出力し、Derived objectに移動します.
int main()
{
    Derived d{};
    Base& bref{ d };
    std::cout << bref << '\n';

    return 0;
}
このとき出力は次のようになります.
Base
これは私たちが望んでいる結果ではありません.

Can we make Operator << virtual?


では、operatoro<<を仮想化できますか?
簡単に言えば、あり得ない.
第一に、member関数のみが仮想化できる
第二に,できれば演算子の定義から,パラメータはそれぞれBase,Derivedである.
では、どうすればいいのでしょうか.

The solution


答えは意外と簡単
メンバー関数の利用
#include <iostream>

class Base
{
public:
	// Here's our overloaded operator<<
	friend std::ostream& operator<<(std::ostream& out, const Base& b)
	{
		// Delegate printing responsibility for printing to member function print()
		return b.print(out);
	}

	// We'll rely on member function print() to do the actual printing
	// Because print is a normal member function, it can be virtualized
	virtual std::ostream& print(std::ostream& out) const
	{
		out << "Base";
		return out;
	}
};

class Derived : public Base
{
public:
	// Here's our override print function to handle the Derived case
	std::ostream& print(std::ostream& out) const override
	{
		out << "Derived";
		return out;
	}
};

int main()
{
	Base b{};
	std::cout << b << '\n';

	Derived d{};
	std::cout << d << '\n'; // note that this works even with no operator<< that explicitly handles Derived objects

	Base& bref{ d };
	std::cout << bref << '\n';

	return 0;
}
printというvirtualmember関数を使用してoperator<<で実行すればよい
従って、出力は以下のようになる
Base
Derived
Derived