2
votes

There is a class A having the virtual method print() and overloaded operator << defined as a friend function.

#include <iostream>
class A
{
public:
    double a1, a2;
    A(): a1(10.0), a2(10.0) {}

    virtual void print ( std::ostream * o = &std::cout ) const
    {
        *o << a1<< '\t' << a2 << '\n';
        }

    friend std::ostream & operator << ( std::ostream & o, const A &aa )
    {
        o << aa.a1 << '\t' << aa.a2 << '\n';
        return o;
    }
};

and analogously in derived class B

 class B : public A
 {
public:
    double b1, b2;
    B(): A(), b1(20.0), b2(20.0) {}

    virtual void print ( std::ostream * o = &std::cout ) const
    {
        A::print ( o );
        *o << b1<< '\t' << b2;
    }

    friend std::ostream & operator << ( std::ostream & o, const B &bb )
    {
        o << (A)(bb);
        o << bb.b1 << '\t' << bb.b2 << '\n';
        return o;
    }
 };

I have the following questions:

1] Is there any way how to pass a pointer to ostream object with default parameter so as operator << correctly replaces the print() method? This overloading is wrong

friend std::ostream & operator << ( std::ostream * o= &std::cout, const A &aa )

2] I am not sure, if this line calling operator of the parent class A in derived class B is correct?

 o << (A)(bb);

3] Is there any better way how to overload operator << without "friend" declaration?

Thanks for your help....

2
Why would you replicate the functionality of print in operator<< when operator<< can simply call print? And then you only need one operator<<(ostream&, const Base&) and it will work for the complete hierarchy. - pmr

2 Answers

1
votes

You can do it like this without friendship:

#include <iostream>
class A
{
    double a1, a2;

public:
    A(): a1(10.0), a2(10.0) {}

    virtual void print ( std::ostream * o = &std::cout ) const
    {
        *o << a1 << '\t' << a2;
    }
};

std::ostream & operator << ( std::ostream & o, const A &aa )
{
    o << "( )";
    aa.print(&o);
    return o << " )";
}

and then class B doesn't a separate version of operator<<, this one will be found, and call B::print when you pass it a B instance.

1
votes

I have long wondered on how to avoid the verbose friend declarations and come up with the following:

template<typename T>
class OutEnabled {
  public:
    friend std::ostream& operator<<(std::ostream& out, T const& val) {
      return static_cast<OutEnabled<T> const&>(val).ioprint(out);
    }

    friend QTextStream& operator<<(QTextStream& out, T const& val) {
      return static_cast<OutEnabled<T> const&>(val).ioprint(out);
    }

    friend QDebug operator<<(QDebug dbg,T const& val) {
      std::stringstream myStream;
      myStream << val;
      dbg.maybeSpace() << myStream.str().c_str();
      return dbg;
    }

  protected:
    template<typename U>
    U& ioprint(U& out) const {
      return static_cast<T const*>(this)->print(out);
    }
};

class Foo:public OutEnabled<Foo>{
  public:
    Foo(){}

    template<typename V>
    V& print(V& out) const{return out<< "Bar";}
};

Writing this I can write:

std::cout << Foo();
qDebug() << Foo();

...

I use this concept a lot since it allows you to specify one print and use it for different streams. I have to use at least the three I mentioned, so for me it is worth the complexity. The friends are out of your class so less typing and it is clear from inheritance that your class is printable. The slight disadvantage is that you have a template in every class that uses OutEnabled.