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!
Related
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.
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>>.
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
here is my problem:
code:
file1.hpp:
namespace Output {
class Stringify{ // base class.....
protected:
size_t prec;
public:
std::stringstream out;
public:
Stringify(const size_t& _p = 5): prec(_p) {out.precision(prec);}
virtual ~Stringify(void){}
public:
std::string operator()(const XYZ& _v){
out.str("");
out << "{ " << _v.x() << ", " << _v.y() << ", " << _v.z() << " }";
return out.str();
}
std::string operator()(const XYZ& _v, const bool& _status){
out << "{ " << _v.x() << ", " << _v.y() << ", " << _v.z() << " }";
return out.str();
}
};
}
where XYZ is a vector object.
file2.hpp:
namespace NODE {
class Stringify: public Output::Stringify {
public:
Stringify2(const size_t& _p = 5): Output::Stringify(_p) {}
virtual ~Stringify2(void){}
public:
std::string operator()(const VERTEX& _obj){ return "What?";}
};
}
where VERTEX is another object with members values of type XYZ
main.cpp:
int main(int argc,char * argv[]){
XYZ v(1,2,3);
NODE::Stringify printer;
cout << printer(v) << endl;
return 0;
}
output is:
What?
when it should:
be {1,2,3}
Compilation is ok but,
As far as I know, NODE::Stringify is able to print {1,2,3}, because of, his base object
has inherit the method for XYZ argument, but it prints the Method with the arguments
of VERTEX (What?). virtual word is not neccesary, because I do not overwrite a method in
the base class.
As a information: I am compiling in MAC OS 10.8 with llvm-gcc-4.2
using Eigen 3.0 libs (typedef Eigen::vector3d XYZ)
Any idea?
Thanks in advance.
Your operator () in the derived class hides the operator () overloads from the base class (which you name Stringify in your example, but that's probably a typo, since the constructor and destructor are named (~)Stringify2).
You can fix this through a using declaration inside the derived class:
namespace NODE {
class Stringify2 : public Output::Stringify {
// ^
public:
using Output::Stringify::operator ();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// This should fix the problem
Stringify2(const size_t& _p = 5): Output::Stringify(_p) {}
virtual ~Stringify2(void){}
public:
std::string operator()(const VERTEX& _obj){ return "What?";}
};
}
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.