#include <iostream>

class Base {
   protected:
      virtual std::ostream & print(std::ostream& stream) const {
         stream << "Base class output\n";
         return stream;
      }
   public:

      // Define it only for the base class.
      friend std::ostream & operator<<(std::ostream & stream, const Base & obj) {
         return obj.print(stream);
      }

      virtual ~Base() {}
};

class A : public Base {

   std::ostream & print(std::ostream & stream) const {
      this->Base::print(stream);
      stream << "foo = " << foo << "\n";
      return stream;
   }

   int foo = 0;
   public:
   ~A() {}
};

class B : public Base {

   std::ostream & print(std::ostream & stream) const {
      this->Base::print(stream);
      stream << "bar = " << bar << "\n";
      return stream;
   }

   int bar = 0;
   public:
   ~B() {}
};


int main(int argc, char * argv[]) {
   Base * base = new Base();
   A * a = new A();
   B * b = new B();
   Base * a_inside = dynamic_cast<Base *>(a);

   std::cout << *base << "\n";
   std::cout << *a << "\n";
   std::cout << *b << "\n";
   std::cout << *a_inside << "\n";

   delete base;
   delete a;
   delete b;

   return 0;
}
