Equivalente in C ++ di Java toString?


151

Vorrei controllare ciò che è scritto in uno stream, ovvero coutper un oggetto di una classe personalizzata. È possibile in C ++? In Java è possibile ignorare il toString()metodo per scopi simili.

Risposte:


176

In C ++ puoi sovraccaricare operator<<per ostreame la tua classe personalizzata:

class A {
public:
  int i;
};

std::ostream& operator<<(std::ostream &strm, const A &a) {
  return strm << "A(" << a.i << ")";
}

In questo modo puoi generare istanze della tua classe su stream:

A x = ...;
std::cout << x << std::endl;

Nel caso in cui operator<<desideri stampare interni di classe Ae abbia davvero bisogno dell'accesso ai suoi membri privati ​​e protetti, puoi anche dichiararlo come funzione amico:

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
È meglio dichiarare l'operatore << come funzione amico della classe in quanto potrebbe essere richiesto per accedere ai membri privati ​​della classe.
Naveen,

5
Meglio ancora dichiararlo come friend, e anche all'interno del corpo della classe - con quello, non dovrai fare using namespaceper lo spazio dei nomi che contiene l'operatore (e la classe), ma ADL lo troverà fintanto che l'oggetto di quella classe è uno degli operandi.
Pavel Minaev,

... quanto sopra voleva dire " definiscilo come amico all'interno del corpo della classe" - come in, una definizione di membro in linea.
Pavel Minaev,

2
@fnieto: quel dumpmetodo pubblico è sporco e non necessario. Usare friendqui va benissimo. Se preferisci un metodo ridondante o invadente friendè una questione di gusti, sebbene friendsia stato probabilmente introdotto per questo preciso scopo.
Konrad Rudolph,

1
@Pavel: la ricerca dipendente dall'argomento la troverà comunque, purché l'operatore sia definito nello stesso spazio dei nomi della classe. Questo non ha nulla a che fare con gli amici e non ha bisogno di essere dichiarato / definito all'interno della classe. Inoltre, creare operator<<()una funzione membro non funzionerà: dovresti renderlo una funzione membro std::ostreamaffinché accetti un operando di tipo sinistro std::ostream.
sth,

50

Puoi anche farlo in questo modo, consentendo il polimorfismo:

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 per la funzione virtuale, per copiare il toStringcomportamento di Java .
Konrad Rudolph,

Perché stupido anziché specificare direttamente l'operatore << nella classe?
monksy

1
perché non vuoi avere un loop infinito e un crash
fnieto - Fernando Nieto,

1
Forse questa tecnica è semplice e veloce per passare opzioni su cosa serializzare. Altrimenti sarebbe necessario definire un altro operatore di amicizia di classe << che è inizializzato con le opzioni e i dati da serializzare.
Samuel Danielson,

Un altro punto sarebbe che l'implementazione della funzionalità di dump potrebbe essere imposta da un'interfaccia, che non sarebbe possibile utilizzando l'operatore proposto.
jupp0r

29

In C ++ 11, to_string viene infine aggiunto allo standard.

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


15
Questa è un'utile aggiunta a questa pagina, tuttavia l'implementazione C ++ è significativamente diversa da quella in Java / C #. In questi linguaggi, ToString()è una funzione virtuale definita sulla classe base di tutti gli oggetti e viene quindi utilizzata come modo standard per esprimere una rappresentazione in forma di stringa di qualsiasi oggetto. Queste funzioni std::stringsi applicano solo ai tipi integrati. Il modo idiomatico in C ++ è di sovrascrivere l' <<operatore per tipi personalizzati.
Drew Noakes,

9
La "bruttezza" della firma standard di operator<<, rispetto alla semplice Stringsemantica di Java, mi spinge a sottolineare che to_string()non è solo "un'utile aggiunta", ma il nuovo modo preferito di farlo in C ++. Se, come per l'OP, Asi desidera una rappresentazione di stringa personalizzata di una classe , basta scrivere una string to_string(A a)definizione di class Asuffissi di seguito. Questo si propaga con l'ereditarietà come in Java e può essere combinato (mediante aggiunta di stringhe) come in Java. Il non overriden toString()in Java ha comunque un uso limitato.
P Marecki,

10

Come estensione a ciò che ha detto John, se vuoi estrarre la rappresentazione di stringa e archiviarla in std::stringquesto modo:

#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::stringstreamsi trova <sstream>nell'intestazione.


2
Questo è un modo ridicolo ingombrante per ottenere una stringa di serializzazione!
Gerd Wagner,

9

Alla domanda è stata data una risposta. Ma volevo aggiungere un esempio concreto.

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

Questo esempio richiede la comprensione del sovraccarico dell'operatore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.