44

In Java, when a class overrides .toString() and you do System.out.println() it will use that.

class MyObj {
    public String toString() { return "Hi"; }
}
...
x = new MyObj();
System.out.println(x); // prints Hi

How can I accomplish that in C++, so that:

Object x = new Object();
std::cout << *x << endl;

Will output some meaningful string representation I chose for Object?

Aillyn
  • 23,354
  • 24
  • 59
  • 84
  • 4
    You shouldn't dynamically allocate the Object with `new` there (it won't compile). – sth Mar 02 '11 at 18:31
  • 4
    in C++, use either `Object* x = new Object(); cout << *x;` or `Object x; cout << x;` – Vlad Mar 02 '11 at 18:35

4 Answers4

62
std::ostream & operator<<(std::ostream & Str, Object const & v) { 
  // print something from v to str, e.g: Str << v.getX();
  return Str;
}

If you write this in a header file, remember to mark the function inline: inline std::ostream & operator<<(... (See the C++ Super-FAQ for why.)

Erik
  • 88,732
  • 13
  • 198
  • 189
  • 18
    Note that this part is NOT in the class / struct! – Martin Thoma Jul 06 '12 at 13:49
  • 1
    The answer about C++ inline functions in the header by @jalf here on SO seems to more clearly answer why to mark function definitions in the header inline than the FAQ did. - http://stackoverflow.com/a/5057179/101151 – jla Jul 11 '16 at 18:26
  • I get error: binary 'operator <<' has too many parameters – Nathan B Jun 20 '18 at 08:12
41

Alternative to Erik's solution you can override the string conversion operator.

class MyObj {
public:
    operator std::string() const { return "Hi"; }
}

With this approach, you can use your objects wherever a string output is needed. You are not restricted to streams.

However this type of conversion operators may lead to unintentional conversions and hard-to-trace bugs. I recommend using this with only classes that have text semantics, such as a Path, a UserName and a SerialCode.

Tugrul Ates
  • 9,451
  • 2
  • 33
  • 59
  • 3
    However, implicit conversion operators like this one can lead to unpleasant surprises. – aschepler Mar 02 '11 at 18:45
  • 1
    It's better to define both, and have `ostream& operator<<` use the `string` operator. Another thing I would do is renaming the `string` operator to something like `ToString()` member function, reserving string cast for the case when the object is itself kind of a string. – Vlad Mar 02 '11 at 18:45
  • 1
    Avoid implicit conversion operators for non-directly-related types. They have a tendency to be the source of some very hard to find bugs if used on types that cannot meaningfully be converted to a specific type. – Zac Howland Mar 02 '11 at 18:51
  • Points taken and added to the answer. – Tugrul Ates Mar 02 '11 at 19:07
6
 class MyClass {
    friend std::ostream & operator<<(std::ostream & _stream, MyClass const & mc) {
        _stream << mc.m_sample_ivar << ' ' << mc.m_sample_fvar << std::endl;
    }

    int m_sample_ivar;
    float m_sample_fvar;
 };
xaxxon
  • 19,189
  • 5
  • 50
  • 80
Parsa Jamshidi
  • 717
  • 5
  • 13
3

Though operator overriding is a nice solution, I'm comfortable with something simpler like the following, (which also seems more likely to Java) :

char* MyClass::toString() {
    char* s = new char[MAX_STR_LEN];
    sprintf_s(s, MAX_STR_LEN, 
             "Value of var1=%d \nValue of var2=%d\n",
              var1, var2);
    return s;
}
Touhid
  • 731
  • 1
  • 10
  • 25
  • 1
    This function won't get called when you use `std::cout << myClassInst;` – Ryan Bemrose Feb 06 '16 at 01:29
  • 2
    As I've stated - it's more likely to Java ... i.e.: It's for usage like: `printf("myClassInst = %s\n", myClassInst.toString() ) ; ` or like: `std::cout << myClassInst.toString() ; ` – Touhid Feb 06 '16 at 05:14