C ++ What's wrong with toString () method

I just stumbled upon this question , which is dedicated to how you can print an object through

std::cout << x << std::endl; 

As I understand it, the standard way to accomplish this is to overload the ostreams <statement. However, this is adding a function to Ostream, not to my class.

An alternative (also asked as an answer to the above question) is to redefine the string conversion operator. However, this is due to a warning about "unintentional conversions and errors with errors."

Now I wonder if there are any flaws in writing the toString () method, and then using it through

 std::cout << x.toString() << std::endl; 
+6
source share
5 answers

Output streams handle output formatting as well as output. Thus, using the toString() method, clients will not be able to control the formatting of the object as they do for everything else:

 // 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 cultural conventions std::cout.imbue(std::locale("")); std::cout << 10000000 << '\n'; // depending on your system configuration may print "10,000,000" 

You may not want to allow formatting, so it may not matter.

Another consideration is that output to the stream does not require the entire string representation to be in memory at the same time, but your toString() method does.


Others have pointed this out, but I think a clearer way of saying that the interface of your classes is not limited only to the methods that it provides, but also includes other functions that you build around it, including non-member functions like both as operator<< overloads that you provide. Even if this is not a method of your class, you should still think of it as part of your class interface.

Here's an article that talks about this that you might find useful: How non-member functions improve encapsulation


Here is a simple example of operator<< overloading for a user-defined class:

 #include <iostream> struct MyClass { int n; }; std::ostream &operator<< (std::ostream &os, MyClass const &m) { for (int i = 0; i < mn; ++i) { os << i << ' '; } return os; } int main() { MyClass c = {1000000}; std::cout << c << '\n'; } 
+3
source

As I understand it, the standard way to accomplish this is to overload the ostreams <statement. However, this is adding a function to ostream, not to my class.

And this is good. The smaller your class, the better. If the popular C ++ idiom allows you to have one more thing from your class, why not follow it?

Now I wonder if there are any flaws in writing the toString () method

Disadvantages:

  • operator<< works the same way with built-in types (for example, int ) and user types. toString can only be accessed by classes
  • C ++ is more heterogeneous than Java. std :: string is the most popular string, but still there are other string classes, and they are used.
  • A string must be created, which could potentially lead to a performance hit. If you write directly to the stream, you avoid this.
+4
source

These are fundamentally different things. Providing operator<< overloads effectively extends the stream interface, making objects of your class type available. Providing the toString function extends the interface of your class, allowing you to get std::string from your class. They represent different things.

The interface of your class should fully correspond to what it represents in your program logic (one responsibility). There is rarely toString natural part of a class interface. However, expanding the stream interface to accept more objects is much more logical.

That is, in one case you say: "Now you can pass objects of this type of class." In another case, you say: "You can turn objects of this type of class into std::string ." - it just so happens that std::string then smooth. Think about it - does it really make sense for my Person class to have a toString function? Since when have I been able to turn people into text?

+3
source

Your first guess is wrong. You do not need to make any changes to ostream.

An operator method similar to the <operator can be defined in two ways: as a method of the ostream class, taking your object x as a parameter, or as a regular old function with two parameters, taking ostream and your x-object as the second parameter as the first parameter.

+1
source

There is nothing wrong with the toString () function for each class. It has the advantages of being more explicit, it can be made polymorphic, and it can be used in situations other than streaming, but when working with a command you need to have an encoding rule ("whether it was to_string () or str (), or streaming ( )? ").

The overload operator <<is more idiomatic. It just takes the ostream parameter as a parameter and makes the conversion implicit in streaming, but since this is idiomatic in C ++, most expect the overloaded operator <when ​​viewing std::cout << x; .

0
source

Source: https://habr.com/ru/post/979038/


All Articles