Operator << in abstract classes, c++ - c++

If I have an abstract class, let's call it "Vertebrate", it has a field std::string name; and it has a pure virtual method
virtual void print(std::ostream&) const noexcept = 0; which will be overridden in child classes and called in operator<<.
I get how polymorphism works, and how to implement the operator<< in inherited classes.
What I don't get:
I don't get this: how to implement an operator<< in that abstract class, that uses the virtual print function. Why this code does not work? My abstract class needs to have operator<<.
virtual void print(std::ostream&) const noexcept = 0;
std::ostream & operator<<(std::ostream & str, Member &obj)
{
return obj.print(str);
}
That is the abstract class code.

You are trying to return the result of print which is void, but operator<< should return std::ostream.
The following should work:
class Vertebrate
{
// ...
virtual void print(std::ostream&) const noexcept = 0;
};
std::ostream& operator<<(std::ostream& stream, Vertebrate& obj)
{
obj.print(stream);
return stream;
}

Related

Overload Resolution: Templatized member function vs friend function for stream operator

Suppose we have this scenario(maybe a little bit artificial)
class OStream
{
virtual void f1() = 0;
...
virtual void f10() = 0;
template<typename T>
OStream& operator<<(const T& t)
{
//doing something
}
};
class MyClass : public OStream
{
virtual void f1() override;
...
virtual void f10() override;
}
In another CPP file, there is another Foo class defined with a friend function like this
friend OStream& operator<<(OStream& ostream, Foo& obj)
{
//doing something with obj
}
Now consider a completely different file that contains such a snippet
...
MyClass obj; //suppose the constructor is defined
Foo foo; //there as well
obj << foo; // which operator is called???? I guess the second one
...
And what operator will be called if I overload OStream::operator<< inside MyClass(it is templated(thus non-virtual), thus I am just hiding the original one?

abstract class overloading ostream operator

I have a basic abstract class Base.
class Base
{
protected:
string m_Name;
public:
virtual string Name() { return m_Name; }
virtual string Type() = 0;
virtual bool isEqual(Base* rhs) = 0 ;
//virtual ostream& operator<< (ostream& out) const;
};
I would like to overload the operator << to display objects that inherit from Base.
I cannot use a void print() function because these objects that inherit from Base also have some objects that can only be displayed by operator <<.
How can I overload the operator << ?
A common pattern is to provide a virtual print method, and use that in an ostream&<< operator:
class Base
{
public:
void print(std::ostream& o) const { /* do your stuff */ }
virtual ~Base() {}
};
std::ostream& operator<<(std::ostream& o, const Base& b)
{
b.print(o);
return o;
}
The idea is that each derived type implements print(ostream&) according to its needs.

Allow stream operator on derived classes

I have an interface that boils down to
class interface
{
protected:
virtual void write(std::string const &) = 0;
};
And derived classes like
class derived : public interface
{
protected:
void write(std::string const & buf)
{
std::cout << buf << std::endl;
}
};
In my application, these objects are passed around as smart pointers, i.e. std::shared_ptr<derived>. I hoped I could overload the << operator, but only for smart pointer of derivatives of my interface. I tried this:
class interface
{
/* ... */
private:
template <typename Derived> friend typename std::enable_if<
std::is_base_of<interface, Derived>::value,
std::shared_ptr<Derived>
>::type & operator<<(std::shared_ptr<Derived> & lhs,
std::string const & rhs)
{
lhs->write(rhs);
return lhs;
}
};
But when I try std::shared_ptr<derived> sp; sp << "test";, the compiler complains that virtual void derived::write(const string&) is protected within this context (this context is my friend function).
Is there a way to achieve this without redundantly writing a stream operator for every derived class?
Why not simply define your operator as:
friend std::shared_ptr<interface> &operator<<(std::shared_ptr<interface> & lhs, std::string const & rhs);
and pass your objects as std::shared_ptr<interface>?

Operator << and inheritance

I have the following classes in C++:
class Event {
//...
friend ofstream& operator<<(ofstream& ofs, Event& e);
};
class SSHDFailureEvent: public Event {
//...
friend ofstream& operator<<(ofstream& ofs, SSHDFailureEvent& e);
};
The code I want to execute is:
main() {
Event *e = new SSHDFailureEvent();
ofstream ofs("file");
ofs << *e;
}
This is a simplification, but what I want to do is write into a file several type of Events
in a file. However, instead of using the operator << of SSHDFailureEvent, it uses the operator << of Event. Is there any way to avoid this behavior?
Thanks
That would not work, as that would call operator<< for the base class.
You can define a virtual function print in base class and re-define it all derived class, and define operator<< only once as,
class Event {
virtual ofstream& print(ofstream & ofs) = 0 ; //pure virtual
friend ofstream& operator<<(ofstream& ofs, Event& e);
};
//define only once - no definition for derived classes!
ofstream& operator<<(ofstream& ofs, Event& e)
{
return e.print(ofs); //call the virtual function whose job is printing!
}
Try:
class Event
{
//...
friend ofstream& operator<<(ofstream& ofs, Event& e)
{
e.print(ofs);
return ofs;
}
virtual void print(std::ofstream& ofs)
{
ofs << "Event\n";
}
};
class SSHDFailureEvent: public Event
{
virtual void print(std::ofstream& ofs)
{
ofs << "SSHDFailureEvent\n";
}
};
The answers so far have the right idea but before you run ahead and implement it, two changes:
Use ostream not ofstream
The print function should be const.
Thus:
class Event
{
public:
virtual ~Event();
virtual std::ostream& printTo( std::ostream& ) const /*= 0*/;
// other public methods
};
/*inline*/ std::ostream& operator<<(std::ostream& os, const Event& event)
{
return event.printTo(os);
}
As long as print (or printTo) is public there is no need to make the stream operator overload a friend.
You have the option of having a default implementation or making the print method pure virtual.
You can also make print() a public non-virtual function that calls a protected or private virtual one, as is the case with all virtual functions.
I see two possibilities here:
Call an explicit print method on the class you are trying to print. For example implement
vritual print(std::ofstream& os);
in the base and the children.
Or -
Attempt to dynamically cast the base class to it's children.
SSHDFailureEvent* fe = dynamic_cast<SSHDFailureEvent*>(new Event());

Making operator<< virtual?

I need to use a virtual << operator. However, when I try to write:
virtual friend ostream & operator<<(ostream& os,const Advertising& add);
I get the compiler error
Error 1 error C2575: 'operator <<' :
only member functions and bases can be
virtual
How can I turn this operator virtual?
The problem with this setup is that the operator<< you defined above is a free function, which can't be virtual (it has no receiver object). In order to make the function virtual, it must be defined as a member of some class, which is problematic here because if you define operator<< as a member of a class then the operands will be in the wrong order:
class MyClass {
public:
virtual ostream& operator<< (ostream& out) const;
};
means that
MyClass myObject;
cout << myObject;
will not compile, but
MyClass myObject;
myObject << cout;
will be legal.
To fix this, you can apply the Fundamental Theorem of Software Engineering - any problem can be solved by adding another layer of indirection. Rather than making operator<< virtual, consider adding a new virtual function to the class that looks like this:
class MyClass {
public:
virtual void print(ostream& where) const;
};
Then, define operator<< as
ostream& operator<< (ostream& out, const MyClass& mc) {
mc.print(out);
return out;
}
This way, the operator<< free function has the right parameter order, but the behavior of operator<< can be customized in subclasses.
You define your operator << to call a virtual print method:
class Base
{
protected:
virtual void print(std::ostream& str) const = 0;
public:
friend std::ostream& operator<<(std::ostream& str, Base const& data)
{
data.print(str);
return str;
}
}
It looks like you really want to provide output functionality for a hierarchy of classes, and if so, you can provide a friend operator << that calls a virtual function.
class Parent
{
public:
friend std::ostream& operator<< (std::ostream& os, const Parent& p);
// ... other class stuff
protected:
virtual void printMyself(std::ostream& os) const
{
// do something if you must, or make this a pure virtual
}
};
std::ostream& operator<< (std::ostream& os, const Parent& p)
{
p.printMyself(os);
return os;
}
class Child : public Parent
{
// other class stuff...
protected:
virtual void printMyself(std::ostream os) const
{
// whatever you need to do
}
};
Also detailed in the C++ FAQ