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());
Related
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?
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;
}
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.
I have a class IDocument which serve as a interface for some classes. It has some abstracts methods (virtual ... = 0).
I would like to do such all subclasses also have to implement an operator for serialization:
In addition to the overloaded stream operators documented here, any Qt classes that you might want to serialize to a QDataStream will have appropriate stream operators declared as non-member of the class:
I'm not even sure how I would make an abstract operator, but how do I define it nonmember?
A non-member operator is a free function, pretty much like any other free function. For QDataStream, on operator<< would look like:
QDataStream& operator<<(QDataStream& ds, SomeType const& obj)
{
// do stuff to write obj to the stream
return ds;
}
In your case, you could implement your serialization like this (this is just one way of doing it, there are others):
#include <QtCore>
class Base {
public:
Base() {};
virtual ~Base() {};
public:
// This must be overriden by descendants to do
// the actual serialization I/O
virtual void serialize(QDataStream&) const = 0;
};
class Derived: public Base {
QString member;
public:
Derived(QString const& str): member(str) {};
public:
// Do all the necessary serialization for Derived in here
void serialize(QDataStream& ds) const {
ds << member;
}
};
// This is the non-member operator<< function, valid for Base
// and its derived types, that takes advantage of the virtual
// serialize function.
QDataStream& operator<<(QDataStream& ds, Base const& b)
{
b.serialize(ds);
return ds;
}
int main()
{
Derived d("hello");
QFile file("file.out");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out << d;
return 0;
}
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