C ++使用toString()方法有什么问题

时间:2014-12-03 10:36:12

标签: c++ string operator-overloading iostream cout

我刚遇到this question,它是关于如何通过

打印对象的
std::cout << x << std::endl;

据我所知,实现这一目标的标准方法是重载ostreams&lt;&lt;运营商。但是,这是为ostream而不是我的班级添加一个功能。

备选方案(也是对上述问题的回答)是覆盖字符串转换运算符。但是,这会带来警告,导致无意的转换和难以追踪的错误&#34;。

现在我想知道编写toString()方法然后通过

使用它是否有任何缺点
std::cout << x.toString() << std::endl;

5 个答案:

答案 0 :(得分:4)

  

据我所知,实现这一目标的标准方法是重载ostreams&lt;&lt;运营商。但是,这是为ostream而不是我的班级添加一个功能。

这是件好事。你的班级越小越好。如果流行的C ++习语允许你在课堂上再做一件事,为什么不跟着它呢?

  

现在我想知道编写toString()方法是否有任何缺点

缺点是:

  • operator<<以内置类型(如int)和用户定义类型的统一方式工作。 toString仅适用于课程
  • C ++比Java更异构。 std :: string是最受欢迎的字符串,但仍然存在其他字符串类,并且它们被使用。
  • 必须创建字符串,这可能会带来性能损失。如果直接写入流,则可以避免使用。

答案 1 :(得分:3)

它们是根本不同的东西。提供operator<<重载有效地扩展了流的接口,使您的类类型的对象可以流式传输。提供toString功能可扩展您班级的界面,从而可以从您的班级中获得std::string。这些代表了不同的东西。

您的类的接口应完全对应于它在程序逻辑中的表示(单一责任)。 toString很少是课程界面的自然部分。但是,扩展流的接口以接受更多对象更为合乎逻辑。

也就是说,在一种情况下,您说“现在您可以流式传输此类类型的对象”。在另一种情况下,您说“您可以将此类类型的对象转换为std::string”。 - 事实恰恰相反,std::string可以流式传输。想一想 - 我的Person课程有toString功能真的有意义吗?从什么时候开始我才能把人变成文字?

答案 2 :(得分:3)

输出流处理输出格式和输出。因此,使用toString()方法,客户端将无法像对待其他所有内容一样管理对象的格式:

// set specific formatting options for printing a value
std::cout << std::scientific << std::setprecision(10) << 10.0 << '\n'; // prints 1.0000000000e+01

// set formatting based on user's cultural conventions
std::cout.imbue(std::locale(""));
std::cout << 10000000 << '\n'; // depending on your system configuration may print "10,000,000"

也许你不在乎允许任何格式化,所以这可能无关紧要。

另一个考虑因素是输出到流并不要求整个字符串表示同时存在于内存中,但是toString()方法会这样做。


其他人已经指出了这一点,但我认为更明确的说法是你的类接口不仅限于它提供的方法,还包括你围绕它构建的其他函数,包括非成员函数,如作为您提供的operator<<重载。即使它不是你班级的一种方法,你仍然应该把它当作你班级界面的一部分。

这篇文章讨论了这个问题,或许你会发现它很有用:How Non-Member Functions Improve Encapsulation


这是一个为用户定义的类重载operator<<的简单示例:

#include <iostream>

struct MyClass {
  int n;
};

std::ostream &operator<< (std::ostream &os, MyClass const &m) {
  for (int i = 0; i < m.n; ++i) {
    os << i << ' ';
  }
  return os;
}

int main() {
  MyClass c = {1000000};
  std::cout << c << '\n';
}

答案 3 :(得分:1)

你的第一个假设是错误的。你不需要在ostream中做任何改变。

运营商方法,如运营商&lt;&lt;可以用两种方式定义:作为ostream类的方法,将x对象作为参数,或者作为具有两个参数的普通旧函数,将ostream作为第一个参数,将x对象作为第二个参数。

答案 4 :(得分:0)

每个类的toString()函数没有任何问题。它具有更明确的优点,可以制作多态,并且可以用于除流之外的其他情况,但是在与团队合作时需要有一个编码规则(&#34;是to_string(),或者str()或streaming()?&#34;)。

重载运算符&lt;&lt;更惯用。它只需要将ostream作为参数并在流式传输时隐式转换,但由于这在C ++中是惯用的,因此大多数都会期望重载的运算符&lt;&lt;看到std::cout << x;时。