C ++ эквивалент ToString Java?


151

Я хотел бы контролировать то, что записывается в поток, т. Е. coutДля объекта пользовательского класса. Это возможно в C ++? В Java вы можете переопределить toString()метод для аналогичной цели.

Ответы:


176

В C ++ можно перегрузить operator<<для 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 << как функцию друга класса, так как это может потребоваться для доступа к закрытым членам класса.
— Навин

5
Еще лучше объявить его как friend, а также внутри тела класса - при этом вам не придется делать это using namespaceдля пространства имен, содержащего оператор (и класс), но ADL найдет его, пока объект этого класса один из операндов.
— Павел Минаев

... вышесказанное должно было сказать « определите его как друга внутри тела класса» - как в определении встроенного члена.
— Павел Минаев

2
@fnieto: этот dumpпубличный метод грязный и ненужный. Использование friendздесь прекрасно. Предпочитаете ли вы избыточный метод или навязчивый friend- это дело вкуса, хотя friend, возможно, оно было введено именно для этой цели.
— Конрад Рудольф

1
@Pavel: поиск, зависящий от аргумента, все равно найдет его, если оператор определен в том же пространстве имен, что и класс. Это не имеет ничего общего с друзьями и не нуждается в том, чтобы это было объявлено / определено внутри класса. Кроме того, создание operator<<()функции-члена не будет работать: вам придется сделать ее функцией-членом, std::ostreamчтобы она принимала левый операнд типа std::ostream.
— STH

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 для виртуальной функции, чтобы скопировать toStringповедение Java .
— Конрад Рудольф

Почему глупее, чем прямо указывать оператор << в классе?
— монахи

1
потому что вы не хотите иметь бесконечный цикл и сбой
— fnieto - Фернандо Ньето

1
Возможно, эта техника быстрая и простая для передачи опций о том, что сериализировать. В противном случае потребуется определить другой оператор связи класса <<, который инициализируется опциями и данными для сериализации.
— Сэмюэль Даниэльсон

Другой момент заключается в том, что реализация функциональности дампа может быть реализована с помощью интерфейса, что будет невозможно при использовании предложенного оператора.
— jupp0r

29

В C ++ 11 to_string наконец добавляется в стандарт.

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


15
Это полезное дополнение к этой странице, однако реализация C ++ значительно отличается от реализации в Java / C #. В этих языках ToString()это виртуальная функция, определенная в базовом классе всех объектов, и поэтому она используется как стандартный способ выражения строкового представления любого объекта. Эти функции std::stringотносятся только к встроенным типам. Идиоматический способ в C ++ - переопределить <<оператор для пользовательских типов.
— Дрю Ноакс

9
«Уродство» стандартной сигнатуры по operator<<сравнению с простой Stringсемантикой Java заставляет меня заметить, что to_string()это не только «полезное дополнение», но и новый предпочтительный способ сделать это в C ++. Если, как и в случае с OP, Aжелательно пользовательское строковое представление класса , достаточно просто написать приведенное string to_string(A a)ниже определение class A. Это распространяется с наследованием, как в Java, и может быть объединено (путем добавления строки), как в Java. Не переопределенный toString()в Java в любом случае имеет ограниченное использование.
— П Марецки

10

В качестве дополнения к тому, что сказал Джон, если вы хотите извлечь строковое представление и сохранить его в 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
Это нелепый и громоздкий способ получения строки сериализации!
— Герд Вагнер

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

Этот пример требует понимания перегрузки оператора.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.