176

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 override the toString() method for similar purpose.

Zoe
  • 27,060
  • 21
  • 118
  • 148
Bogdan Balan
  • 6,493
  • 8
  • 25
  • 23

5 Answers5

196

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 its 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
  • 222,467
  • 53
  • 283
  • 367
  • 5
    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 Oct 11 '09 at 05:45
  • ... the above was meant to say "_define_ it as friend inside the body of the class" - as in, an inline member definition. – Pavel Minaev Oct 11 '09 at 05:48
  • 2
    @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 Oct 11 '09 at 13:32
  • 1
    @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 Oct 11 '09 at 13:37
57

You can also do it this way, allowing polymorphism:

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

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

std::ostream& operator<<(std::ostream& o, const Base& b) { return b.dump(o); }
Fernando N.
  • 6,369
  • 4
  • 27
  • 30
  • 4
    +1 for virtual function, to copy Java's `toString` behaviour. – Konrad Rudolph Oct 11 '09 at 13:33
  • Why dumb rather than directly specifying operator<< in the class? – monksy Jul 19 '10 at 14:38
  • 1
    beacause you don't want to have an infinite loop and a crash – Fernando N. Jul 29 '10 at 18:08
  • 1
    Perhaps this technique is fast and easy for passing options on what to serialize. Otherwise it would be required to define another class friending operator<< that is initialized with the options and the data to serialize. – Samuel Danielson Mar 20 '12 at 22:48
  • Another point would be that the implementation of the dump functionality could be enforced by an interface, which would not be possible using the proposed operator. – jupp0r Apr 02 '14 at 10:00
  • Somehow I need to add "const" like virtual std::ostream& dump(std::ostream& o) const { ... } – Qi Fan Feb 03 '16 at 05:14
  • Best from this answer is that it would allow to print also child classes – Bogdan Mart Aug 11 '21 at 04:31
  • I dont like this approach, it couples it too strongly, and inheritance used this way can lead to combinatoric explosion of classes, as you end up with classes of all the combinations of the features you want which is 2^n. Put the functionality in its own template function outside the class. – user904542 Jun 05 '23 at 11:02
33

In C++11, to_string is finally added to the standard.

http://en.cppreference.com/w/cpp/string/basic_string/to_string

Zhaojun Zhang
  • 489
  • 4
  • 10
  • 17
    This is a useful addition to this page, however the C++ implementation is significantly different to the one in Java/C#. In those languages, `ToString()` is a virtual function defined on the base class of *all* objects, and is therefore used as a standard way to express a string representation of any object. These functions on `std::string` only apply to built-in types. The idiomatic way in C++ is to override the `<<` operator for custom types. – Drew Noakes Mar 01 '13 at 20:26
  • 12
    The "ugliness" of the standard signature of `operator<<`, as compared to simple `String` semantics of Java prompts me to remark, that `to_string()` is not only "a useful addition", but the new preferred way to do it in C++. If, as by the OP, a custom string representation of a class `A` is desired, just writing a `string to_string(A a)` below definition of `class A` suffices. This propagates with inheritance as in Java, and can be combined (by string addition) as in Java. Non-overriden `toString()` in Java is of limited use anyway. – P Marecki Jan 19 '16 at 22:27
12

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

#include <sstream>    
// ...
// 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.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
blwy10
  • 4,862
  • 2
  • 24
  • 23
  • 3
    That's a ridiculous cumbersome way for obtaining a serialization string! – Gerd Wagner Mar 05 '16 at 15:35
  • You could make that a template function outside the class, that can takes a T& where T has a the operator<< overloaded and have that return a string – user904542 Jun 05 '23 at 10:59
11

The question has been answered. But I wanted to add a concrete example.

class Point{

public:
      Point(int theX, int theY) :x(theX), y(theY)
      {}
      // Print the object
      friend ostream& operator <<(ostream& outputStream, const Point& p);
private:
      int x;
      int y;
};

ostream& operator <<(ostream& outputStream, const Point& p){
       int posX = p.x;
       int posY = p.y;

       outputStream << "x="<<posX<<","<<"y="<<posY;
      return outputStream;
}

This example requires understanding operator overload.