Making operator<< virtual?
Solution 1
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.
Hope this helps!
Solution 2
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;
}
}
Solution 3
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
inna karpasas
Updated on July 09, 2022Comments
-
inna karpasas over 1 year
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?
-
inna karpasas about 13 yearsthanks it is very helpful. i thought a bout this solution,but i thought maybe There is another way that I do not know that easier for implementation.
-
Kos about 13 years"any problem can be solved by adding another layer of indirection" - remember, any problem except the problem of too many layers of indirection ;)
-
James McNellis about 13 years@Kos: No, no. As long as you've declared it
unsigned indirection;
, you just have to keep adding more and more indirection and the problem will solve itself when you roll over -
Gene Bushuyev about 13 yearsyou probably meant
data.print(str);
-
Daniel Trebbien about 13 yearsIn addition to @Gene's comment, the pure virtual function needs to be protected so that non-friend derived classes can implement it.
-
Martin York about 13 years@Daniel Trebbien: You could just as easily leave it as private and it will still be implementable. But I agree protected is probably a good idea.
-
Daniel Trebbien about 13 yearsInteresting! I didn't think that that was legal, but it apparently works: codepad.org/NGOA87Bn
-
Martin York about 13 years@Daniel Trebbien: In the derived class it can be public or private and it will still work (Java/C# are more strict about this. You can not make something less protected in a derived class). Though it is considered bad practice to make the access less restrictive in a derived class.