tags:

views:

540

answers:

4

I'd like to control what is written to a stream, i.e. cout, for an object of a custom class. Is that possible in C++? In Java you could overwride the toString() method for similar purpose. Thanks

+19  A: 

In C++ you can overload operator<< for ostream and your custom class:

class A {
public:
  int i;
};

std::ostream& operator<<(std::ostream &strm, const A &a) {
  return strm << "A(" << a.i << ")";
}

This way you can output instances of your class on streams:

A x = ...;
std::cout << x << std::endl;

In case your operator<< wants to print out internals of class A and really needs access to it's private and protected members you could also declare it as a friend function:

class A {
private:
  friend std::ostream &operator<<(std::ostream&, const A&);
  int j;
};

std::ostream& operator<<(std::ostream &strm, const A &a) {
  return strm << "A(" << a.j << ")";
}
sth
It is better to declare the operator<< as friend function of the class as it might be required to access the private members of the class.
Naveen
Better yet declare it as `friend`, and also inside the body of the class - with that, you won't have to do `using namespace` for the namespace containing the operator (and the class), but ADL will find it so long as object of that class is one of operands.
Pavel Minaev
... the above was meant to say "_define_ it as friend inside the body of the class" - as in, an inline member definition.
Pavel Minaev
@Naveen, that friend is dirty and unnecessary. Write a dump public method, and call it from a free operator<< function.
fnieto
@fnieto: that `dump` public method is dirty and unnecessary. Using `friend` here is perfectly fine. Whether you prefer a redundant method or an intrusive `friend` is entirely a matter of taste, although `friend` has arguably been introduced for this exact purpose.
Konrad Rudolph
@Pavel: Argument dependent lookup will find it anyway, as long as the operator is defined in the same namespace as the class. This has nothing to to with friends and doesn't need it to be declared/defined inside the class. Also, making `operator<<()` a member function won't work: you would have to make it a member function of `std::ostream` for it to accept a left hand operand of type `std::ostream`.
sth
@Konrad: you are already making public dump functionality trough operator<<, so I don't see anything dirty about its public access. dump method has nothing to do with the friend but with polymorphic behavior, you could make dump private and keep the friend but I insist, it is ugly and unnecessary.
fnieto
A: 

sprintf

'nuf said

sprintf_nuf_said
then why go that far..use good old printf.
Naveen
sprintf is a C not C++ construct, as such it does not have the notion of the representation of a custom class, plus it does not play nice with iostream.
Chen Levy
sprintf_nuf_said, given your user name I understand that you have a certain affinity for sprintf. I do think that its suitability in this particular case can be questioned, but I certainly expect many more sprintf-centered answers from you! How do you do this in SQL? sprintf! How do I do that in Java? sprintf! How does a hash table work? sprintf! What is important to think of when managing a large programming project? sprintf!
Thomas Padron-McCarthy
+2  A: 

As an extension to what John said, if you want to extract the string representation and store it in a std::string do this:

// Suppose a class A
A a;
std::stringstream sstream;
sstream << a;
std::string s = sstream.str(); // or you could use sstream >> s but that would skip out whitespace

std::stringstream is located in the <sstream> header.

blwy10
The header is <sstream>
Jonas
Oops... dang. Sorry about that.
blwy10
+3  A: 

You can do it without unnecessary friends and allowing polymorphism, this way:

class Base {
public:
   virtual std::ostream& dump(std::ostream& o) {
      return o << "Base: " << b << "; ";
   }
private:
  int b;
};

class Derived : public Base {
public:
   virtual std::ostream& dump(std::ostream& o) {
      return o << "Derived: " << d << "; ";
   }
private:
   int d;
}

std::ostream& operator<<(std::ostream& o, const Base& b) { return b.dump(o); }
fnieto
+1 for virtual function, to copy Java's `toString` behaviour.
Konrad Rudolph
Why dumb rather than directly specifying operator<< in the class?
monksy
beacause you don't want to have an infinite loop and a crash
fnieto