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
Краще оголосити оператора << як функцію друзів класу, оскільки це може знадобитися для доступу до приватних членів класу.
Naveen

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 .
Конрад Рудольф

Чому німий, а не безпосередньо вказуючи оператора << у класі?
monksy

1
тому що ви не хочете мати нескінченний цикл і аварію
fnieto - Фернандо Нієто,

1
Можливо, ця методика швидко і легко передає варіанти того, що потрібно серіалізувати. В іншому випадку потрібно буде визначити іншого оператора фріндингу класів <<, який ініціалізується з параметрами та даними для серіалізації.
Самуель Даніельсон

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

29

У C ++ 11 тонінгрінг нарешті додається до стандарту.

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 ++. Якщо, як це стосується ОП, Aбажане представлення рядка класу на замовлення , просто записуючи string to_string(A a)нижченаведене визначення class Aдостатності. Це поширюється з успадкуванням, як у Java, і може поєднуватися (шляхом додавання рядків), як у Java. Непереборка toString()на Java в будь-якому разі обмежена.
P Marecki

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.