【问题标题】:C++ equivalent of Java's toString?C++ 等价于 Java 的 toString?
【发布时间】:2009-10-11 05:28:39
【问题描述】:

我想为自定义类的对象控制写入流的内容,即cout。这在 C++ 中可能吗?在 Java 中,您可以覆盖 toString() 方法以实现类似目的。

【问题讨论】:

    标签: c++


    【解决方案1】:

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

    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&lt;&lt; 想要打印出 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 << ")";
    }
    

    【讨论】:

    • 最好将其声明为friend,并且也在类的主体内 - 这样,您不必为包含运算符(和类)的命名空间执行using namespace ,但只要该类的对象是操作数之一,ADL 就会找到它。
    • ... 上面的意思是说“define 它是类主体内的朋友” - 如内联成员定义。
    • @fnieto:dump 公共方法是肮脏且不必要的。在这里使用friend 非常好。您是否喜欢冗余方法或侵入性 friend 完全取决于个人喜好,尽管可以说引入了 friend 就是为了这个目的。
    • @Pavel:只要操作符定义在与类相同的命名空间中,依赖于参数的查找无论如何都会找到它。这与朋友无关,也不需要在类中声明/定义。此外,将operator&lt;&lt;() 设为成员函数也行不通:您必须将其设为std::ostream 的成员函数才能接受std::ostream 类型的左操作数。
    【解决方案2】:

    你也可以这样做,允许多态性:

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

    【讨论】:

    • +1 表示虚函数,复制 Java 的 toString 行为。
    • 为什么愚蠢而不是直接在类中指定运算符
    • 因为你不希望有无限循环和崩溃
    • 也许这种技术可以快速轻松地传递有关序列化内容的选项。否则,将需要定义另一个类友好运算符
    • 另一点是转储功能的实现可以通过接口强制执行,而使用建议的运算符则无法实现。
    【解决方案3】:

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

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

    【讨论】:

    • 这是对本页有用的补充,但是 C++ 实现与 Java/C# 中的实现有很大不同。在那些语言中,ToString() 是在 all 对象的基类上定义的虚函数,因此被用作表达任何对象的字符串表示的标准方式。 std::string 上的这些函数仅适用于内置类型。 C++ 中的惯用方式是为自定义类型覆盖 &lt;&lt; 运算符。
    • operator&lt;&lt; 的标准签名的“丑陋”,与 Java 的简单 String 语义相比,提示我说,to_string() 不仅是“一个有用的补充”,而且在 C++ 中执行此操作的新首选方法。如果像 OP 一样,需要类 A 的自定义字符串表示,只需在 class A 的定义下方编写 string to_string(A a) 就足够了。这与 Java 中的继承一起传播,并且可以像 Java 中一样组合(通过字符串添加)。无论如何,Java 中的非覆盖 toString() 的使用是有限的。
    【解决方案4】:

    作为 John 所说的扩展,如果您想提取字符串表示并将其存储在 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 位于&lt;sstream&gt; 标头中。

    【讨论】:

    • 这是获取序列化字符串的荒谬繁琐的方式!
    【解决方案5】:

    问题已得到解答。但我想添加一个具体的例子。

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

    这个例子需要理解运算符重载。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-01
      • 2013-05-26
      • 2010-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多