Is this the only way of overloading the ostream& operator<< for a derived class without duplicating code for the base class? Are the casts not something to be avoided?
I don't see any other way, except to define some kind of function in the base class that will represent the data of the base class as something that std::operator<< could "eat up" (like a string?), doing the same thing for the derived class (calling the base class stream representation function within the derived class stream. rep. function of course).
What is the ideal solution to this problem?
#include <iostream>
class Base
{
private:
int b_;
public:
Base()
:
b_()
{};
Base (int b)
:
b_(b)
{};
friend std::ostream& operator<<(std::ostream& os, const Base& b);
};
std::ostream& operator<< (std::ostream& os, const Base& b)
{
os << b.b_;
return os;
}
class Derived
:
public Base
{
private:
int d_;
public:
Derived()
:
d_()
{};
Derived (int b, int d)
:
Base(b),
d_(d)
{};
friend std::ostream& operator<<(std::ostream& os, const Derived& b);
};
std::ostream& operator<< (std::ostream& os, const Derived& b)
{
os << static_cast<const Base&>(b) << " " << b.d_;
return os;
}
using namespace std;
int main(int argc, const char *argv[])
{
Base b(4);
cout << b << endl;
Derived d(4,5);
cout << d << endl;
return 0;
}
Well ... casting should be avoided if done in contexts where the result is not correctly defined, but casting into a base is always safe.
It is possible to avoid the explicit cast by considering that a derived reference decays into the base reference, so you can use an implicit conversion, like in this case:
std::ostream& operator<< (std::ostream& os, const Derived& b)
{
const Base& bs = b;
os << bs << " " << b.d_;
return os;
}
static_cast<const Base&>(b)
is safe and there is nothing incorrect, because every derived class object is also an Base class object and can be treated like one.
Casts are dangerous only when used in a reckless way, You must use casts where they are needed and in a correct manner, that is the very purpose of their provision by the language standard.
If you don't like the casts, you can have your operator call a writeTo function that is implemented using the template method pattern.
e.g.
class Base {
public:
std::ostream& writeTo(std::ostream& ostr) const { os << b_; return this->doWriteTo(os); }
private:
int b_;
virtual std::ostream& doWriteTo(std::ostream& ostr) const = 0; // pure virtual
};
class Derived {
private:
int d_;
virtual std::ostream& doWriteTo(std::ostream& ostr) const {return ostr << d_;}
};
std::ostream& operator<<(std::ostream& ostr, const Derived& d) {
return d.writeTo(ostr);
}
Actually, using this pattern, you can write operator<< once and for all for Base:
std::ostream& operator<<(std::ostream& ostr, const Base& b) {
return b.writeTo(ostr);
}
This pattern also elminates the need to make operator<< a friend.
You could change things around like this:
struct Base {
int b_;
void print(ostream &o) { o << b_; }
};
struct Derived : Base {
int d_;
void print(ostream &o) {
Base::print(o);
o << ' ' << d_;
}
};
ostream &operator<<(ostream &o, Base &b) {
b.print(o);
return o;
}
ostream &operator<<(ostream &o, Derived &d) {
d.print(o);
return o;
}
If Base had virtual functions (which in this example it doesn't), then print could be one of them, and you could get rid of the multiple overloads of operator<<.
Related
I have a base b and a derived d classes.
Within operator<< for d (which is not a class member) I want to call operator<< for b, plus other actions.
I used static_cast for that.
Is there any other way to achieve the same?
What are pros and cons of the alternatives?
class b {
};
class d : public b {
};
ostream& operator<<(ostream& os, const b& bi) {
os << "base";
return os;
}
ostream& operator<<(ostream& os, const d& di) {
// call operator for the base class...;
os << static_cast<b>(di) << endl;
os << " ... and derived";
return os;
}
This would be better handled by defining only 1 operator<< for just b, and then add a virtual method in b for that operator<< to call, and then have d override that method, eg:
class b {
public:
virtual void printTo(ostream& os) const;
};
class d : public b {
public:
void printTo(ostream& os) const override;
};
ostream& operator<<(ostream& os, const b& bi) {
bi.printTo(os);
return os;
}
void b::printTo(ostream& os) const {
os << "base";
}
void d::printTo(ostream& os) const {
b::printTo(os);
os << endl << " ... and derived";
}
I have two classes, base and derived. In main I have a vector which is *base type and contains one base object and one derived object. I have overloaded output operator for both classes, but when I print the vector for derived class, base output operator is called although I have overloaded it separately. What should I change in my program to change output from:
12
30
to
12
30 31
?
This is the code:
#include <iostream>
#include <vector>
using namespace std;
class base {
int x;
public:
base(int _x) : x(_x) {}
friend ostream& operator<<(ostream& out, base obj) {
return out << obj.x;
}
};
class derived : public base {
int y;
public:
derived(int _x, int _y) : base(_x), y(_y) {}
friend ostream& operator<<(ostream& out, derived obj) {
return out << (base) obj << ' ' << obj.y;
}
};
int main() {
vector<base*> vec;
base* a = new base(12);
derived* b = new derived(30,31);
vec.push_back(a);
vec.push_back(b);
for (auto p: vec) cout << *p << '\n';
}
Dynamic dispatch, based on the underlying object, works only for virtual member functions. It does not work for non-member functions or non-virtual member functions.
One way to get around the problem would be:
Use the friend function using the base type.
Change the argument type for obj to be a const reference.
From that function, call a virtual member function to do the real work.
class base {
int x;
public:
base(int _x) : x(_x) {}
virtual std::ostream& write(std::ostream& out) const
{
return (out << x);
}
// Change obj to be a const reference
friend std::ostream& operator<<(std::ostream& out, base const& obj)
{
return obj.write(out);
}
};
class derived : public base {
int y;
public:
derived(int _x, int _y) : base(_x), y(_y) {}
virtual std::ostream& write(std::ostream& out) const
{
// Let the base class take care of its part.
base::write(out);
// Now take care of this class part.
return ( out << ' ' << y);
}
// This is useless now.
// friend ostream& operator<<(ostream& out, derived obj) {
// return out << (base) obj << ' ' << obj.y;
// }
};
PS Why is "using namespace std;" considered bad practice?
This question already has answers here:
Templates and overloadering operator << [duplicate]
(5 answers)
Closed 7 years ago.
I'm trying to implement a sort of virtual operator << that lets me send a IBase class object to cout so that it calls the Derived class' operator <<. Is this possible?
class IBase
{
public:
IBase() {};
virtual ~IBase() {};
};
template <typename T>
class Derived
: public IBase
{
public:
Derived(T data);
template <typename U>
friend std::ostream& operator<<(std::ostream& os, const Derived<U>& dt);
private:
T data_;
};
template <typename T>
Derived<T>::Derived(T data)
: IBase(),
data_(data)
{
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const Derived<T>& dt)
{
os << dt.data_;
return os;
}
int _tmain(int argc, _TCHAR* argv[])
{
IBase* base = new Derived<int>(5);
std::cout << *base;
}
The << operator is a function, not a method and thus it can not be virtual. However you can still achieve what you want- remember that the operator<< takes a reference as parameter? Well polymorphism works on those too. Simply add another virtual method that you call from the << operator.
Have a look at this short example I put together:
#include <iostream>
#include <string>
using namespace std;
class Base {
public:
virtual string toString() const {
return "base";
}
};
class Child : public Base {
public:
virtual string toString() const {
return "child";
}
friend ostream& operator<<(ostream& out, const Base& b);
};
ostream& operator<<(ostream& out, const Base& b) {
out << b.toString();
return out;
}
int main() {
Child c;
cout << c;
return 0;
}
And here is a link in ideone: http://ideone.com/EmP1oP
Your goal can't be attained through templates alone as dereferencing a IBase* gets you a IBase& - template instantiation occurs at compile time and the compiler has no access to the runtime type.
(Dynamic dispatch only happens when you invoke a member function of an object, and a binary operator can't be a member of its right-hand operand.)
So your templated operator will never be used if you pass a dereferenced IBase* to operator <<.
Instead, add a virtual output function to the base and override it:
class IBase
{
public:
IBase() {};
virtual ~IBase() {};
virtual std::ostream& output(std::ostream&) const = 0;
};
template <typename T>
class Derived
: public IBase
{
public:
Derived(T data);
virtual std::ostream& output(std::ostream& os) const
{
os << data;
return os;
}
private:
T data_;
};
std::ostream& operator<<(std::ostream& os, const IBase& dt)
{
return dt.output(os);
}
You can make it virtual for real with a help of simple template rig (which, in addition, does not prevent de-virtualization).
struct X {
virtual std::ostream& repr(std::ostream& out) const;
}
template <class X>
std::enable_if_t<
std::is_same<
std::void_t<
decltype(std::declval<X>().repr(std::declval<std::ostream>()))>,
void>::value,
std::ostream&>
operator<<(X const& x)
{
return x.repr(out);
}
class Vehicle{
long Number;
int Year;
char *Make,*Model,*BodyStyle,*Color;
float Cost;
friend ostream & operator<<(ostream& stream,const Vehicle& v);
class TruckVehicle:public Vehicle{
int Passengers;
long Mileage,GrossWeight,TempGross;
char *PoweredBy;
friend ostream & operator<<(ostream& stream,const TruckVehicle& t )
in the above code ..how do i call the overloaded << of the base class to the << function of derived class??
replies will be highly appreciated.
Simplest and cleanest way to do this is:-
class Base
{
public:
virtual ostream& put(ostream& s) const = 0;
};
ostream& operator<<(ostream& s, const Base& r)
{
return r.put(s);
}
class Derived : public Base
{
public:
ostream& put(ostream& s) const;
};
void f(const Base b, Derived d)
{
cout << b << d;
}
i.e put() is a virtual function that ensures that the right output operation is used in <<.
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