2

EDIT: the code had a typo, now it compiles but I am still not getting the output I want.

I am attempting to overload the stream operator for std::cout, std::fstream, etc, but I am not being able to handle polymorphism properly: I am not able to get the output I want to see. I would like the subclasses to show the content of the superclass and then its content, while the superclass to show only its content. This can be achieved by introducing a new function print_only_base() in the Base function, but I suspect that I can make the code working even without adding a new function.

What I want to get

I have a base class which has some attributes that I want to be showed on screen when I do

Base base;
std::cout << base;

There are two classes, A and B which inherits from Base. Base is a polymorphic class and A and B are showing different output when streamed.

I want an object of class Base to show only its output, while an object of class A (the same for B) to show first the output itself if seen as an instance of Base and then the output of itself seen as A (or B).

Below the code I write the output I would expect and my (not working) attempt.

#include <iostream>

class Base {
    virtual std::ostream & print(std::ostream stream) const {
        stream << "Base class output\n";
        return stream;
    }
public:
    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 {
        stream << "foo = " << foo << "\n";
        return stream;
    }
    int foo = 0;
public:
    friend std::ostream & operator<<(std::ostream & stream, const A & obj) {
        // here I would like to call the base class for printing, but I would enter in an infinite loop
        return obj.print(stream);
    }
    ~A() {}
};

class B : public Base {
    std::ostream & print(std::ostream & stream) const {
        stream << "bar = " << bar << "\n";
        return stream;
    }
    int bar = 0;
public:
    friend std::ostream & operator<<(std::ostream & stream, const B & obj) {
        // here I would like to call the base class for printing, but I would enter in an infinite loop
        return obj.print(stream);
    }
    ~B() {}
};

Main function:

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;

    /* output I want to get
       Base class output

       Base class output
       foo = 0

       Base class output
       bar = 0

       Base class output
       foo = 0
    */


    return 0;
}

How can I get the desired behaviour?

Nisba
  • 3,210
  • 2
  • 27
  • 46
  • 1
    Did you try passing `std::ostream` by reference? – Algirdas Preidžius Apr 18 '18 at 15:39
  • Uh, that is only a typo fortunately! The compiler error is gone, but still I am not getting the desired output (see the last comment on the code for classes) – Nisba Apr 18 '18 at 15:41
  • 1
    Then it is a dupe of [this](https://stackoverflow.com/questions/357307/how-to-call-a-parent-class-function-from-derived-class-function). You need `return Base::print(stream)` – NathanOliver Apr 18 '18 at 15:43
  • @NathanOliver I added this `return obj.Base::print(stream);` and made `print` protected in the base class, but I am not getting the correct output. – Nisba Apr 18 '18 at 15:51
  • I've retracted my close vote. You'll need more changes as pointed out in the answer below. – NathanOliver Apr 18 '18 at 15:58
  • 1
    Remove `friend std::ostream & operator<<` in the derived classes, IMO the base class's overload should be able to handle the derived ones too. Then in the overridden `print()` methods, call `Base::print()` first. – zett42 Apr 18 '18 at 16:01

1 Answers1

6

The solution is very simple.

  1. Define the operator<< function only for the base class. There is no need to define it for the derived types.
  2. Rely on the virtual function mechanism to invoke the print function of the derived class.
  3. Add code to call Base::print from the derived classes before printing the derived class specific content. Make sure the function is not private in the base class.

#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 {
      // Print the base class specific information first.
      Base::print(stream);

      // Print the derived class specific information.
      stream << "foo = " << foo << "\n";
      return stream;
   }

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

class B : public Base {

   std::ostream & print(std::ostream & stream) const {
      // Print the base class-specific information first.
      Base::print(stream);

      // Print the derived class specific information.
      stream << "bar = " << bar << "\n";
      return stream;
   }

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

With those changes, I get the desired output. See it working at https://ideone.com/x6ti3W.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 1
    Working great, thanks! I think that the return value of print is redundant, I can make it void, call `obj.print(stream)` in `Base` and then return `stream`. – Nisba Apr 18 '18 at 16:01
  • `this->` before `Base::print` can be removed. – zett42 Apr 18 '18 at 16:03
  • @Nisba, you're welcome. Yes, you can change the return type of `print` to `void` without affecting the functionality. – R Sahu Apr 18 '18 at 16:05