相当于Java的toString的C ++?


151

我想控制写入流的内容,即cout针对自定义类的对象。在C ++中有可能吗?在Java中,您可以toString()出于类似目的重写该方法。

Answers:


176

在C ++中,您可以重载operator<<for ostream和您的自定义类:

class A {
public:
  int i;
};

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

这样,您可以在流上输出类的实例:

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

如果您operator<<希望打印出类的内部结构A并且确实需要访问其私有成员和受保护成员,则还可以将其声明为朋友函数:

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 << ")";
}

16
最好将operator <<声明为类的朋友函数,因为可能需要访问operator <<来访问类的私有成员。
Naveen

5
更好的是将其声明为friend,并且也声明为类的主体内的内容-这样,您就不必using namespace对包含运算符(和该类)的名称空间进行操作,但是只要该类的对象是ADL,它就可以找到它。操作数之一。
2009年

...上面的意思是说“ 定义为类主体内的朋友”-就像内联成员定义一样。
帕维尔·米纳夫

2
@fnieto:该dump公共方法是肮脏且不必要的。使用friend此处非常好。friend尽管friend可以说是为了这个确切的目的而引入的,但是您是选择冗余方法还是侵入式方法完全取决于口味。
康拉德·鲁道夫2009年

1
@Pavel:只要运算符在与类相同的名称空间中定义,依赖于参数的查找将始终找到它。这与朋友无关,也不需要在类中声明/定义。同样,使operator<<()成员函数不起作用:您必须使其成为其成员函数,std::ostream才能接受type的左手操作数std::ostream
某事

50

您也可以通过这种方式来实现多态:

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); }

3
+1为虚函数,复制Java的toString行为。
Konrad Rudolph

为什么要笨而不是直接在类中指定operator <<?
僧侣2010年

1
因为您不想遇到无限循环和崩溃
fnieto-Fernando Nieto,2010年

1
也许这项技术可以快速简便地传递序列化选项。否则,将需要定义另一个类的友好操作符<<,该类用选项和要序列化的数据初始化。
塞缪尔·丹尼尔森

另一点是转储功能的实现可以通过接口来实现,而使用建议的运算符则不可能。
jupp0r 2014年

28

在C ++ 11中,最终将to_string添加到标准中。

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


15
这是对该页面的有用补充,但是C ++实现与Java / C#中的实现明显不同。在这些语言中,ToString()是在所有对象的基类上定义的虚函数,因此用作表示任何对象的字符串表示形式的标准方法。这些功能std::string仅适用于内置类型。C ++中的惯用方式是重写<<自定义类型的运算符。
Drew Noakes

9
operator<<StringJava的简单语义相比 ,的标准签名的“丑陋” 促使我指出,这to_string()不仅是“有用的补充”,而且还是C ++中实现该目标的新首选方式。如果像OP那样A需要一个类的自定义字符串表示形式,则只需编写string to_string(A a)下面的定义class A就足够了。就像Java中那样,它是通过继承传播的,并且可以像Java中那样进行组合(通过添加字符串)。toString()无论如何,在Java中不可覆盖是有限的。
P Marecki '16

10

作为对约翰所说内容的扩展,如果要提取字符串表示形式并将其存储在a中,std::string请执行以下操作:

#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位于<sstream>标题中。


2
这是获得序列化字符串的荒谬繁琐方式!
Gerd Wagner'3

9

问题已经回答。但我想添加一个具体的例子。

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;
}

此示例需要了解操作员重载。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.