C ++ equivalente ao toString de Java?

151

Eu gostaria de controlar o que é gravado em um fluxo, ou seja cout, para um objeto de uma classe personalizada. Isso é possível em C ++? Em Java, você pode substituir o toString()método para fins semelhantes.

Bogdan Balan
fonte

Respostas:

176

Em C ++, você pode sobrecarregar operator<<para ostreame sua classe personalizada:

class A {
public:
  int i;
};

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

Dessa maneira, você pode gerar instâncias da sua classe nos fluxos:

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

Caso você operator<<deseje imprimir páginas internas da classe Ae realmente precise acessar seus membros particulares e protegidos, você também pode declarar isso como uma função de amigo:

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 << ")";
}
sth
fonte
16
É melhor declarar o operador << como função amiga da classe, pois pode ser necessário acessar os membros privados da classe.
Naveen
5
Melhor ainda declará-lo como friend, e também dentro do corpo da classe - com isso, você não terá que fazer using namespacepelo espaço para nome que contém o operador (e a classe), mas a ADL o achará enquanto o objeto dessa classe for um dos operandos.
Pavel Minaev 11/10/2009
... o texto acima deveria dizer " defina -o como amigo dentro do corpo da classe" - como em uma definição de membro embutido.
Pavel Minaev 11/10/2009
2
@ Fnieto: esse dumpmétodo público é sujo e desnecessário. Usar friendaqui é perfeitamente bom. Se você prefere um método redundante ou um intrusivo, friendé uma questão de gosto, embora friendtenha sido discutido com esse objetivo exato.
11139 Konrad Rudolph
1
@ Pavel: a pesquisa dependente de argumento a encontrará de qualquer maneira, desde que o operador esteja definido no mesmo espaço de nome da classe. Isso não tem nada a ver com amigos e não precisa ser declarado / definido dentro da classe. Além disso, criar operator<<()uma função de membro não funcionará: você precisaria torná-la uma função de membro std::ostreampara aceitar um operando do tipo à esquerda std::ostream.
sth
50

Você também pode fazer dessa maneira, permitindo o 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); }
fnieto - Fernando Nieto
fonte
3
+1 para função virtual, para copiar o toStringcomportamento do Java .
11289 Konrad Rudolph
Por que burro, em vez de especificar diretamente o operador << na classe?
22410 Monksy
1
beacause você não quer ter um loop infinito e um acidente
fnieto - Fernando Nieto
1
Talvez essa técnica seja rápida e fácil para passar opções sobre o que serializar. Caso contrário, seria necessário definir outro operador amigo da classe << que seja inicializado com as opções e os dados a serem serializados.
Samuel Danielson
Outro ponto seria que a implementação da funcionalidade de despejo poderia ser imposta por uma interface, o que não seria possível usando o operador proposto.
jupp0r
29

No C ++ 11, to_string é finalmente adicionado ao padrão.

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

Zhaojun Zhang
fonte
15
Esta é uma adição útil a esta página, no entanto, a implementação do C ++ é significativamente diferente da implementação em Java / C #. Nessas linguagens, ToString()é uma função virtual definida na classe base de todos os objetos e, portanto, é usada como uma maneira padrão de expressar uma representação de seqüência de caracteres de qualquer objeto. Essas funções se std::stringaplicam apenas a tipos internos. A maneira idiomática no C ++ é substituir o <<operador por tipos personalizados.
de Drew Noakes
9
A "feiúra" da assinatura padrão operator<<, em comparação com a simples Stringsemântica de Java, me leva a observar que isso to_string()não é apenas "uma adição útil", mas a nova maneira preferida de fazê-lo em C ++. Se, como no OP, uma representação de string personalizada de uma classe Afor desejada, basta escrever uma string to_string(A a)definição abaixo de class Asuficiente. Isso se propaga com herança como em Java e pode ser combinado (por adição de sequência) como em Java. De qualquer forma, o domínio não substituído toString()em Java é de uso limitado.
Marecki
10

Como uma extensão do que John disse, se você deseja extrair a representação de string e armazená-la, std::stringfaça o seguinte:

#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::stringstreamestá localizado no <sstream>cabeçalho.

blwy10
fonte
2
Essa é uma maneira ridícula e complicada de obter uma string de serialização!
Gerd Wagner
9

A pergunta foi respondida. Mas eu queria adicionar um exemplo 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;
}

Este exemplo requer a compreensão da sobrecarga do operador.


fonte