A: Provide a friend operator<< which calls a protected virtual function
class Base {
public:
friend std::ostream& operator<< (std::ostream& o, const Base& b);
... protected:
virtual void printOn(std::ostream& o) const;
};
inline std::ostream& operator<< (std::ostream& o, const Base& b)
{ b.printOn(o); return o;
}
class Derived : public Base {
protected:
virtual void printOn(std::ostream& o) const;
};
The ending result is that operator<< acts as if it were bound dynamically, even though it's a friend function. It is called the Virtual Friend Function Idiom.
Note down that derived classes override printOn(std::ostream&) const. Particularly, they do not provide their own operator<<.
Of course if Base is an ABC, Base::printOn(std::ostream&) const may be declared pure virtual using the "= 0" syntax.
!