Printing derived object using operator<< overload not working - c++

Why can I not print the derived object using this approach? How can I fix this so that the derived printout prints "derived size=8". I ideally want to keep the printing code out of the class code.
#include <iostream>
class base
{
public:
base(int size) : size_(size) {}
virtual int get_size() const { return size_; }
private:
int size_;
};
std::ostream& operator<<(std::ostream& os, const base& obj) {
os << "base size=" << obj.get_size() << std::endl;
return os;
}
class derived1 : public base
{
public:
derived1(int size) : base(size) {}
virtual int get_size() const {
return 2 * base::get_size();
}
};
std::ostream& operator<<(std::ostream& os, const derived1& obj) {
os << "derived1 size=" << obj.get_size() << std::endl;
return os;
}
int main(int argc, char* argv[]) {
base* b1 = new base(3);
std::cout << "b1 size is: " << b1->get_size() << std::endl;
std::cout << *b1 << std::endl;
base* b2 = new derived1(4);
std::cout << "b2 size is: " << b2->get_size() << std::endl;
std::cout << *b2 << std::endl;
delete b1;
delete b2;
return 0;
}
Output:
b1 size is: 3
base size=3
b2 size is: 8
base size=8
UPDATE:
I changed as follows as per ghostsofstandardspast which works:
#include <iostream>
class base
{
public:
base(int size) : size_(size) {}
virtual int get_size() const { return size_; }
friend std::ostream& operator<<(std::ostream &os, const base& obj);
private:
virtual std::ostream &print(std::ostream &os) const {
return os << "base size=" << get_size() << std::endl;
}
int size_;
};
std::ostream& operator<<(std::ostream& os, const base& obj) {
obj.print(os);
return os;
}
class derived1 : public base
{
public:
derived1(int size) : base(size) {}
virtual int get_size() const {
return 2 * base::get_size();
}
friend std::ostream& operator<<(std::ostream &os, const derived1& obj);
private:
virtual std::ostream &print(std::ostream &os) const {
return os << "derived1 size=" << get_size() << std::endl;
}
};
int main(int argc, char* argv[]) {
base* b1 = new base(3);
std::cout << "b1 size is: " << b1->get_size() << std::endl;
std::cout << *b1 << std::endl;
base* b2 = new derived1(4);
std::cout << "b2 size is: " << b2->get_size() << std::endl;
std::cout << *b2 << std::endl;
return 0;
}

operator<< is not a virtual member function, so it can't be used polymorphically like other member functions can. Instead, you should delegate to a virtual member.
Change both of your operator<< overloads to a virtual member function called print or something similar. Then, overload operator<< to delegate to that:
std::ostream &operator<<(std::ostream &os, const Base &obj) {
obj.print(os); //or whatever name you choose
return os;
}
If you want to make the member function private, make operator<< a friend.
Finally, note that printing a pointer to an object of your class will only print the address. To invoke operator<<, you need to print the object itself:
Base *b = /*whatever*/;
std::cout << *b;
This technique for a polymorphic operator<< is demonstrated in this cppquiz question. I highly recommend going through those questions.

cout << b2 doesn't invoke your operator <<, because b2 is a pointer not a reference. Try cout << *b2 instead.

It doesn't work because in a call
std::cout << b1 << std::endl;
you are printing an address, since b1 is a pointer ( i.e. 0x8e02008).
You should dereference it instead
std::cout << *b1 << std::endl;
In this case both for *b1 and *b2 objects the std::ostream& operator<<(std::ostream& os, const base& obj); will be calles and virtual call to get_size() will be executed.
ideone

Related

C++ Function overload in the child

I have a parent DataType class from which I inherit Data Type Int, DataType Double, DataTypeEnum
and CDataTypeStruct. Somewhere I use the print () method defined by the parent and somewhere I rewrite it. I call the print method using the << operator.
Why, when I call a title for the CDataTypeEnum type, everything is displayed correctly, as I have the print defined in the CDaraTypeEnum.
I get this
struct {
int int enum}
but if I want to list cout << structure << endl; so for the CDataTypeStruct type, I don't get an overloaded print method for each object?
Just to make the statement look like this
struct {
int int
enum {
NEW,
FIXED,
BROKEN,
DEAD
}
}
--
All program https://onecompiler.com/cpp/3y2rhbm7a and here's a minimal reproducible example:
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>
using namespace std;
class CDataType
{
public:
CDataType(string type, size_t size);
friend ostream& operator << (ostream &os, CDataType &x);
virtual ostream& print (ostream &os) const;
protected:
string m_Type;
size_t m_Size;
};
CDataType::CDataType(string type, size_t size)
: m_Type(type),
m_Size(size)
{
}
ostream& operator << (ostream &os, CDataType &x)
{
x.print(os);
return os;
}
ostream& CDataType::print (ostream &os) const
{
os << m_Type;
return os;
}
class CDataTypeInt : public CDataType
{
public:
CDataTypeInt();
};
CDataTypeInt::CDataTypeInt()
: CDataType("int", 4)
{
}
class CDataTypeEnum : public CDataType
{
public:
CDataTypeEnum();
CDataTypeEnum& add(string x);
virtual ostream& print (ostream &os) const;
protected:
vector<string> listEnums;
set<string> listEnumsNames;
};
CDataTypeEnum::CDataTypeEnum()
: CDataType("enum", 4)
{
}
ostream& CDataTypeEnum::print(ostream &os) const
{
os << m_Type << "{\n";
for (auto i=listEnums.begin(); i != listEnums.end(); ++i )
{
os << *i;
if(i != listEnums.end()-1)
{
os << ",";
}
os << "\n";
}
os << "}";
return os;
}
CDataTypeEnum& CDataTypeEnum::add(string x)
{
if(listEnumsNames.find(x) == listEnumsNames.end())
{
listEnums.push_back(x);
listEnumsNames.emplace(x);
}
else
cout << "vyjimkaa" << endl;
// CSyntaxException e("Duplicate enum value: " + x);
return *this;
}
class CDataTypeStruct : public CDataType
{
public:
virtual ostream& print (ostream &os) const;
CDataTypeStruct();
CDataTypeStruct& addField(const string &name, const CDataType &type);
protected:
list<unique_ptr<CDataType>> m_Field;
unordered_set<string> m_Field_names;
};
CDataTypeStruct::CDataTypeStruct()
:CDataType("struct", 0)
{
}
CDataTypeStruct& CDataTypeStruct::addField(const string &name, const CDataType &type)
{
if( m_Field_names.find(name) == m_Field_names.end() )
{
m_Field.push_back(make_unique<CDataType>(type));
m_Field_names.emplace(name);
}
// else
//throw CSyntaxException("Duplicate field: " + name);
return *this;
}
ostream& CDataTypeStruct::print (ostream &os) const
{
os << m_Type << "{\n";
for(const auto &uptr : m_Field)
{
uptr->print(os) << " " /*<< "{\n"*/;
}
os << "}";
return os;
}
int main()
{
CDataTypeInt inta;
CDataTypeInt intb;
CDataTypeStruct struktura;
CDataTypeEnum enumos;
enumos.add( "NEW" ).add ( "FIXED" ) .add ( "BROKEN" ) .add ( "DEAD" );
struktura.addField("integera", inta);
struktura.addField("integerb", intb);
struktura.addField("bbb", enumos);
cout << enumos << endl;
cout << struktura << endl;
}```
As I already suggested in a similar question you posted already (and deleted), you're again slicing here:
struktura.addField("integera", inta); // Slicing
struktura.addField("integerb", intb); // Slicing
struktura.addField("bbb", enumos); // Slicing
Again, consider following guideline "A polymorphic class should suppress public copy/move" from the C++ Core Guidelines. To do this:
class CDataType {
public:
// ...
// Disable move and copy
CDataType(CDataType const &) = delete;
CDataType(CDataType &&) = delete;
CDataType& operaror=(CDataType const &) = delete;
CDataType& operaror=(CDataType &&) = delete;
// Dtor should be virtual.
virtual ~CDataType() = default;
// ...
};
Then, adapt your code accordingly (as it won't compile anymore).
Also, The destructor of CDataType should be virtual.
Edit: Please consider the following example, which hopeful makes the slicing issue clearer:
#include <cstdio>
#include <list>
#include <memory>
struct A {
A() = default;
A(A const&) { std::puts("A(A const&)"); }
virtual ~A() { std::puts("~A()"); }
};
struct B : public A {
B() = default;
B(B const&) { std::puts("B(B const&)"); }
~B() override { std::puts("~B()"); }
};
void slicing_addField(A const& a) {
std::puts("slicing_f");
std::list<std::unique_ptr<A>> l;
l.push_back(std::make_unique<A>(a));
}
void non_slicing_addField(std::unique_ptr<A> a) {
std::puts("non_slicing_f");
std::list<std::unique_ptr<A>> l;
l.push_back(std::move(a));
}
int main() {
// This is what you do
slicing_addField(B{});
// This is how you may solve
non_slicing_addField(std::make_unique<B>());
}
Output:
slicing_f
A(A const&)
~A()
~B()
~A()
non_slicing_f
~B()
~A()
As you can see from the output, you're only calling A(A const&) in slicing_addField.
This means the call to make_unique<A>(a) is allocating an object of run-time type A (while you want it of run-time type B).
The main problem is that you try to copy the CDataType decendant in addField by using make_unique<CDataType>, but that actually creates a CDataType, not a CDataTypeInt, CDataTypeEnum or CDataTypeStruct.
Since constructors can't be virtual (in standard C++) you need to create a separate virtual function to do the copying. A common name for such a function is clone. Example:
class CDataType {
public:
CDataType(string type, size_t size);
CDataType(const CDataType&) = delete;
CDataType& operator=(const CDataType&) = delete;
virtual ~CDataType() = default; // add virtual dtor
virtual std::unique_ptr<CDataType> clone() const {
return std::make_unique<CDataType>(m_Type, m_Size);
}
// ...
};
class CDataTypeEnum : public CDataType {
public:
using CDataType::CDataType;
std::unique_ptr<CDataType> clone() const override {
// use make_unique to create the correct type:
auto np = std::make_unique<CDataTypeEnum>(m_Type, m_Size);
np->listEnums = listEnums;
np->listEnumsNames = listEnumsNames;
return np;
}
// ...
};
class CDataTypeStruct : public CDataType {
public:
using CDataType::CDataType;
std::unique_ptr<CDataType> clone() const override {
// use make_unique to create the correct type:
auto np = std::make_unique<CDataTypeStruct>(m_Type, m_Size);
np->m_Field_names = m_Field_names;
for(auto& cdtp : m_Field)
np->m_Field.emplace_back(cdtp->clone()); // use clone here
return np;
}
// ...
};
Then addField would look like this:
CDataTypeStruct& CDataTypeStruct::addField(const string& name,
const CDataType& type) {
if (m_Field_names.find(name) == m_Field_names.end()) {
m_Field.emplace_back(type.clone()); // and use clone here
m_Field_names.emplace(name);
}
return *this;
}

Autodeduction of return type

After reading C++ auto deduction of return type and C++ : Vector of template class, I'm still wondering how to do generic operations (e.g. operator << overload) on object. My code looks like
#include <map>
#include <memory>
#include <string>
#include <iostream>
/**
* Abstract placeholder for Cache polymorphism
*/
class ICache
{
public:
virtual void update() {};
friend std::ostream & operator << (std::ostream & out, const ICache & IC)
{
out << "you should never print this";
}
};
/**
* Concrete. Coupling a name with some cached value
*/
template<typename T>
class Cache :
public ICache
{
const std::string m_name;
T m_cached;
public:
Cache(const std::string & name) :
m_name(name),
m_cached(0)
{}
void update() override
{
// m_cached is synced with remote resource; action depends both from T and m_name
}
void set(const T t)
{
std::cout << m_name << " setting " << +m_cached << " -> " << +t << std::endl;
m_cached = t;
}
inline T get() const noexcept { return m_cached; }
friend std::ostream & operator << (std::ostream & out, const Cache & O)
{
out << "Cache<" << O.m_name << ", " << O.m_cached << ">";
}
};
class CacheMap
{
std::map<std::string, std::unique_ptr<ICache>> m_map;
template<typename T>
Cache<T>* _get_ptr(const std::string & name) const
{
return reinterpret_cast<Cache<T>*>(m_map.at(name).get());
}
public:
template<typename T>
T get(const std::string & name) const
{
return _get_ptr<T>(name)->get();
}
template <typename T>
void set(const std::string & name, T t)
{
_get_ptr<T>(name)->set(t);
}
template <typename T>
void insert(const std::string & name, T def = 0)
{
std::unique_ptr<ICache> up = std::make_unique<Cache<T>>(name);
m_map.insert({name, std::move(up)});
set<T>(name, def);
}
friend std::ostream & operator << (std::ostream & out, const CacheMap & OM)
{
out << "OM{";
for (const auto & IO : OM.m_map)
out << IO.first << ": " << *(IO.second.get()) << ", "; // ver1
// out << IO.first << ": " << (IO.second->get()) << ", "; // ver2
out << "}";
return out;
}
};
int main()
{
CacheMap m;
int i= 70000;
m.insert<int>("i", 69999);
m.insert<short>("s", 699);
m.insert<char>("c", 69);
m.set("i", i);
std::cout << m << std::endl;
}
Line marked with trailing //ver1 shows you should never print this which makes sense; I'm dealing with std::unique_ptr<ICache> objects.
Line marked with trailing //ver2 won't compile at all, and this makes sense too.
What I'd like to do inside CacheMap is to auto-detect, at runtime (hmm sounds bad) the correct T, given a map key, in order to fire the right reinterpret_cast<> and to retrieve m_cached value.
EDIT 1
If compiling with g++ -O3, ver1 line causes a segmentation violation.
Just use a virtual function. The time you cast your variable from Cache<int> pointer type to ICache pointer you lose compile time information about it. That information is lost. You can use dynamic_cast in your friend ICache::operator<< to handle all the different types... To properly resolve type information use virtual functions - ie. unique data tied to each of the class.
#include <map>
#include <memory>
#include <string>
#include <iostream>
class ICache
{
public:
virtual ~ICache() {};
virtual void update() {};
// -------- HERE --------------
virtual std::ostream& printme(std::ostream & out) const = 0;
friend std::ostream& operator << (std::ostream & out, const ICache & IC) {
return IC.printme(out);
}
};
template<typename T>
class Cache : public ICache {
const std::string m_name;
T m_cached;
public:
Cache(const std::string & name): m_name(name), m_cached(0) {}
void update() override {}
void set(const T t) {
std::cout << m_name << " setting " << +m_cached << " -> " << +t << std::endl;
m_cached = t;
}
inline T get() const noexcept { return m_cached; }
std::ostream& printme(std::ostream & out) const override {
out << "Cache<" << m_name << ", " << m_cached << ">";
return out;
}
};
class CacheMap {
std::map<std::string, std::unique_ptr<ICache>> m_map;
template<typename T>
Cache<T>* _get_ptr(const std::string & name) const {
return dynamic_cast<Cache<T>*>(m_map.at(name).get());
}
public:
template<typename T>
T get(const std::string & name) const {
return _get_ptr<T>(name)->get();
}
template <typename T>
void set(const std::string & name, T t) {
_get_ptr<T>(name)->set(t);
}
template <typename T>
void insert(const std::string & name, T def = 0) {
std::unique_ptr<ICache> up = std::make_unique<Cache<T>>(name);
m_map.insert({name, std::move(up)});
set<T>(name, def);
}
friend std::ostream& operator << (std::ostream & out, const CacheMap & OM) {
out << "OM{";
for (const auto & IO : OM.m_map)
out << IO.first << ": " << *(IO.second.get()) << ", "; // ver1
// out << IO.first << ": " << (IO.second->get()) << ", "; // ver2
out << "}";
return out;
}
};
int main()
{
CacheMap m;
int i= 70000;
m.insert<int>("i", 69999);
m.insert<short>("s", 699);
m.insert<char>("c", 69);
m.set("i", i);
std::cout << m << std::endl;
}
will output on godbolt:
i setting 0 -> 69999
s setting 0 -> 699
c setting 0 -> 69
i setting 69999 -> 70000
OM{c: Cache<c, E>, i: Cache<i, 70000>, s: Cache<s, 699>, }
I just spotted, to protect against very bad and hard to debug errors, I remind you to use dynamic_cast instead of reintepret_cast in CacheMap::_get_ptr().
There are various ways, but generally I would implement a single operator<<() that calls a virtual function.
class ICache {
protected: // so the function is only accessible to derived classes
virtual std::ostream print(std::ostream &out) const = 0; // force derived classes to override
friend std::ostream &operator<<(std::ostream &out, const ICache& c);
};
Then place a single definition of the operator<< in a single compilation unit
// definition of class ICache needs to be visible here
std::ostream &operator<<(std::ostream &out, const ICache& c)
{
return c.print(out);
}
And to implement the derived class
// definition of ICache here
template<class T>
class Cache: ICache
{
protected:
std::ostream print(std::ostream &out) const override
{
// output a Cache<T>
return out;
}
};
The advantage of this is that each class takes responsibility for outputting itself, rather than a container class having to work out which output function to call (and the opportunity for a programmer to forget to do that).
First, reinterpret_cast is a dangerous thing. In contexts of polymorphism you mostly want to use dynamic_cast.
You problem is not about templates etc at all, but it is more about that you want to make the operator<< virtual, which is not possible, since it is a friend function. An easy workaround is the following:
class ICache {
virtual void print(std::ostream &out) const { // Prefer pure virtual
out << "Never print this\n";
}
friend std::ostream &operator<<(std::ostream &out, const ICache& c) {
c.print(out);
return out;
}
};
template<class T>
class Cache: ICache {
void print(std::ostream &out) const override {
out << "Print this instead\n";
}
};
will do what you want without any casting.

Polymorphism does not work with pointers, operator<< overload, inheritance, C++

I have a problem with my code. I have two classes, A and B, and B inherits A. I also have operators << overloaded in both classes.
Everything works, I have no compiler errors, but it seems something is wrong. As far as I understand polymorphism, when I use pointers to base class while creating child class with new, calling a method should match the child class, not the base class.
For the code below,
#include <iostream>
using namespace std;
class A
{
protected:
int a;
public:
A(int aa) : a(aa) {};
virtual void show(ostream& o) const
{
o << "a = " << a << "\n";
}
};
ostream& operator << (ostream& os, const A &o)
{
o.show(os);
return os;
}
class B : public A
{
private:
int b;
public:
B(int bb, int aa) : A(aa), b(bb){}
int getb() const {return b;}
};
ostream & operator << ( ostream & os, const B & o)
{
os << static_cast <const A &>(o);
os << "\n";
os << "b = " << o.getb() << "\n";
return os;
}
int main()
{
A *o1 = new B(2,3);
cout << *o1;
cout << "---------------------\n";
B *o2 = new B(2,3);
cout << *o2;
return 0;
}
In main:
A *o1 = new B(2,3);
cout << *o1;
Shows a = 3, instead of showing a = 3 b = 2 (the call should match the child class, not the base class). The thing is, I need to implement the << and >> operators in every child class, but I think they do not behave as they should.
The output of the program:
Even the modified code with re-implmented show method shows wrong results, it does not show a at all this time:
#include <iostream>
using namespace std;
class A
{
protected:
int a;
public:
A(int aa) : a(aa) {};
virtual void show(ostream& o) const
{
o << "a = " << a << "\n";
}
};
ostream& operator << (ostream& os, const A &o)
{
o.show(os);
return os;
}
class B : public A
{
private:
int b;
public:
B(int bb, int aa) : A(aa), b(bb) {}
int getb() const
{
return b;
}
void show(ostream& o) const
{
o << "b = " << b << "\n";
}
};
ostream & operator << ( ostream & os, const B & o)
{
os << static_cast <const A &>(o);
o.show(os);
return os;
}
int main()
{
A *o1 = new B(2,3);
cout << *o1;
cout << "---------------------\n";
B *o2 = new B(2,3);
cout << *o2;
return 0;
}
enter image description here
you have to implement the virtual function show in derived class B:
class B: public A
{
public:
// some code here
virtual void show(ostream& o) const
{
o << "b = " << b << "\n";
}
};
when I use pointers to base class while creating child class with new,
calling a method should match the child class, not the base class
It does when you call a member function ("method" in some other languages), but operator<< is not a member function – it's an overloaded free function.
When choosing an overload, only the types known at compile-time are used.
Since o1 is an A*, *o1 is an A&, and the overload for A& is chosen.
You're doing this a bit "backwards"; you only need one operator<<, for the base class, which calls the virtual show, and then you override show in the derived classes.
Like this:
class A
{
// ...
virtual void show(ostream& o) const
{
o << "a = " << a << "\n";
}
};
ostream& operator << (ostream& os, const A &o)
{
o.show(os);
return os;
}
class B : public A
{
// ...
void show(ostream& o) const override
{
A::show(o); // Do the "A part".
o << "b = " << b << "\n";
}
};
Follow the same pattern for operator>>.

Derived Members and Overloaded Ostream Operator

Working with a large number of derived classes whose members I would like to display with the << operator. As more classes are used it will likely become quite cumbersome to override the operator/other functions for the new members. I was curious if there was a way to accomplish something similar to the following? Which of course, will overflow.
// Base class
class Foo {
public:
friend ostream& operator <<(ostream& outputStream, const Foo& foo) {
outputStream << foo.fooName + ": " + foo.fooInfo + ", ";
return outputStream;
}
protected:
string fooName;
string fooInfo;
};
// Foo Derived class
class FooBar : public Foo {
public:
friend ostream& operator <<(ostream& outputStream, const FooBar& fooBar) {
outputStream << fooBar; // (fooBar.fooName + ": " + fooBar.fooInfo + ", ")
outputStream << fooBar.barName + ": " + fooBar.barInfo + ", ";
return outputStream;
/* The above as opposed to:
outputStream << fooBar.fooName + ": " + fooBar.fooInfo + ", " <<
fooBar.barName + ": " + fooBar.barInfo + ", "; */
}
protected:
string barName;
string barInfo;
};
If something similar (recursive) is not possible, what is an alternative solution? IE passing different argument(s) or calling an ostream/other function return within the operator body. Thanks.
This may help you out, however the Base class In this case is completely Abstract! Here are the Base & 2 Derived Classes
#include <conio.h>
#include <string>
#include <iostream>
class Base {
friend std::ostream& operator<<( std::ostream& out, const Base* const pObj );
private:
std::string m_strName;
public:
std::string getName() const { return m_strName; }
virtual ~Base(){} // Default Okay
protected:
explicit Base( std::string strName ) : m_strName( strName ) {}
virtual void printData( std::ostream& out ) const = 0;
};
std::ostream& operator<<( std::ostream& out, const Base* const pObj ) {
out << pObj->m_strName << std::endl;
pObj->printData( out );
return out;
}
class DerivedA : public Base {
private:
int m_value;
public:
explicit DerivedA( int& a ) : Base( std::string( "DerivedA" ) ), m_value( a ) {}
protected:
virtual void printData( std::ostream& out ) const override;
};
void DerivedA::printData( std::ostream& out ) const {
out << "Value: " << m_value;
}
class DerivedB : public Base {
private:
float m_value;
public:
explicit DerivedB( float& f ) : Base( std::string( "DerivedB" ) ), m_value( f ) {}
protected:
virtual void printData( std::ostream& out ) const override;
};
void DerivedB::printData( std::ostream& out ) const {
out << "Value: " << m_value;
}
int main () {
int a = 4;
float b = 3.2f;
DerivedA derivedA( a );
DerivedB derivedB( b );
// Notice I Used The Address Of Operator Here Due To How The << operator Is Defined
std::cout << &derivedA << std::endl << std::endl;
std::cout << &derivedB << std::endl << std::endl;
std::cout << "Press any key to quit" << std::endl;
_getch();
return 0;
}
Another way to use this instead of on the stack would be on the heap but make sure to clean up all memory.
int main () {
int a = 4;
float b = 3.2f;
DerivedA derivedA = new DerivedA( a );
DerivedB derivedB = new DerviedB( b );
// Since This Is On The Heap I Can Use The Class Directly
std::cout << derivedA << std::endl << std::endl;
std::cout << derivedB << std::endl << std::endl;
// Make Sure To Clean Up Memory
delete derivedA;
delete derivedB;
std::cout << "Press any key to quit" << std::endl;
_getch();
return 0;
}
What I ended up doing here is I created a friend << operator in the Base Class that will call a printData() function that is defined as being a purely virtual method. Remember that you can not construct a Base object directly since it is completely Abstract. Here each Derived type will have to implement its own printData() function! This way each class will know how to use the << operator since it is defined in the base class that it is inherited from. This is the power of Inheritance. So now I only have to defined the overloaded operator once and can use it for every derived type, but all derived types must specify a printData() function since each derived type may have different internal data that you would like to have printed.
If you do not want to use the pointer notation as I have defined within my Base Class << operator declaration & definition you can do it this way as well:
class Base {
friend std::ostream& operator<<( std::ostream& out, const Base& obj );
// Everything Else Is The Same As Before
};
std::ostream& operator<<( std::ostream& out, const Base& obj ) {
out << obj.m_strName << std::endl;
obj.printData( out );
}
int main() {
// Everything Is Same As Before As In The First main() example
// Except For The Two std::cout Statements Where As Here You
// Can Use The Objects Directly Instead Of Using The Address Of Operator
std::cout << derivedA << std::endl;
std::cout << derivedB << std::endl;
// Rest Is Same As Before.
}
If you want you can include both versions in your base class so that the stream operator << knows how to print your class either by object, reference or pointer!

What undesirable results occur when casting to parent class object instead of reference?

This code was written by Bruce Eckel in his book "Thinking in C++" Chapter 14 page 649. What I didn't understand was the comment he made below [emphasis added]:
The operator<< for Child is interesting because of the way that it calls the operator<< for the Parent within it : by casting the Child object to a Parent&
(if you cast to a base-class object instead of a reference you will usually get undesirable results).
Here's the corresponding code:
#include <iostream>
using namespace std;
class Parent
{
int i;
public:
Parent(int ii) : i(ii) { cout << "Parent(int ii)\n"; }
Parent(const Parent& b) : i(b.i) { cout << "Parent(const Parent&)\n"; }
Parent() : i(0) { cout << "Parent()\n"; }
friend ostream& operator<<(ostream& os, const Parent& b) {
return os << "Parent: " << b.i << endl;
}
};
class Member
{
int i;
public:
Member(int ii) : i(ii) { cout << "Member(int ii)\n"; }
Member(const Member& m) : i(m.i) { cout << "Member(const Member&)\n"; }
friend ostream& operator<<(ostream& os, const Member& m) {
return os << "Member: " << m.i << endl;
}
};
class Child : public Parent
{
int i;
Member m;
public:
Child(int ii) : Parent(ii), i(ii), m(ii) { cout << "Child(int ii)\n"; }
friend ostream& operator<<(ostream& os, const Child& c) {
return os << (Parent&)c << c.m << "Child: " << c.i << endl;
}
};
int main()
{
Child c(2);
cout << "calling copy-constructor: " << endl;
Child c2 = c;
cout << "values in c2:\n" << c2;
}
That's probably object slicing meant. That is, you'll lose some parts of your object by copying it into an instance of the parent class (instead of assigning a reference).
also have a look at the answers to this question:
What is object slicing?
Here's an example: (see http://ideone.com/qeZoa)
#include <iostream>
using namespace std;
struct parent {
virtual const char* hi() const { return "I'm your father..."; }
};
struct child : public parent {
const char* hi() const { return "No way!"; }
};
int main() {
child c;
cout << ((parent) c).hi() << endl;
cout << ((parent&)c).hi() << endl;
}
Yes this is okay . Parent and Child are Polymorphic. as Child inherit's Client you can cast a Child& to Parent&
In expression os << (Parent&)c rhs (Parent&)c is of type Parent& So the operator<<(ostream& os, const Parent& b) will be called from operator<<(ostream& os, const Child& b)
In C++ Polymorphism only works when you have reference or Pointer type
The undesirable result is that the compiler has to create a temporary copy of the Parent portion of the Child object, pass a reference to that temporary to the inserter, and then destroy the temporary. That's a lot of churning...
And, as #NeelBasu hinted, if Parent has virtual functions that are overridden in Child, calls to those functions from the inserter won't call the Child version, because the object passed in is a Parent object.