|
||||
Section 15:
|
[15.11] How can I provide printing for an entire hierarchy of classes?
Provide a friend operator<< that calls a protected virtual function: class Base { public: friend std::ostream& operator<< (std::ostream& o, Base const& b); ... protected: virtual void printOn(std::ostream& o) const = 0; ← or plain virtual; see below }; inline std::ostream& operator<< (std::ostream& o, Base const& b) { b.printOn(o); return o; } class Derived : public Base { public: ... protected: virtual void printOn(std::ostream& o) const; }; void Derived::printOn(std::ostream& o) const { ... }The end result is that operator<< acts as if it were dynamically bound, even though it's a friend function. This is called the Virtual Friend Function Idiom. Note that derived classes override printOn(std::ostream&) const. In particular, they do not provide their own operator<<. As to whether Base::printOn() is plain virtual or pure virtual, consider making it a plain virtual (without the "= 0") if you can implement that function with code that would otherwise be repeated in two or more derived classes. However if Base is a ABC with little or no member data, you might not be able to provide a meaningful definition for Base::printOn() and you should make it pure virtual. If you're not sure, make it pure virtual, at least until you get a better handle on the derived classes. |