C ++ setara dengan toString Java?


151

Saya ingin mengontrol apa yang ditulis ke aliran, yaitu cout, untuk objek kelas kustom. Apakah itu mungkin di C ++? Di Jawa Anda bisa mengganti toString()metode untuk tujuan yang sama.

Jawaban:


176

Di C ++ Anda dapat kelebihan operator<<untuk ostreamdan kelas khusus Anda:

class A {
public:
  int i;
};

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

Dengan cara ini Anda dapat menampilkan instance kelas Anda di stream:

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

Jika Anda operator<<ingin mencetak internal kelas Adan benar-benar membutuhkan akses ke anggota pribadi dan terlindungi, Anda juga dapat mendeklarasikannya sebagai fungsi teman:

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
Lebih baik menyatakan operator << sebagai fungsi teman kelas karena mungkin diperlukan untuk mengakses anggota pribadi kelas.
Naveen

5
Lebih baik mendeklarasikannya sebagai friend, dan juga di dalam tubuh kelas - dengan itu, Anda tidak harus melakukan using namespaceuntuk namespace yang berisi operator (dan kelas), tetapi ADL akan menemukannya selama objek kelas itu adalah salah satu operan.
Pavel Minaev

... di atas dimaksudkan untuk mengatakan " mendefinisikannya sebagai teman di dalam tubuh kelas" - seperti dalam, definisi anggota inline.
Pavel Minaev

2
@ Fieto: dumpmetode publik itu kotor dan tidak perlu. Penggunaan di friendsini baik-baik saja. Apakah Anda lebih suka metode yang berlebihan atau intrusif friendsepenuhnya adalah masalah selera, meskipun friendmungkin telah diperkenalkan untuk tujuan yang tepat ini.
Konrad Rudolph

1
@Pavel: Pencarian bergantung argumen akan tetap menemukannya, selama operator didefinisikan dalam namespace yang sama dengan kelas. Ini tidak ada hubungannya dengan teman dan tidak perlu dideklarasikan / didefinisikan di dalam kelas. Juga, membuat operator<<()fungsi anggota tidak akan berfungsi: Anda harus menjadikannya fungsi anggota std::ostreamagar dapat menerima operan tipe tangan kiri std::ostream.
sth

50

Anda juga dapat melakukannya dengan cara ini, memungkinkan polimorfisme:

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 untuk fungsi virtual, untuk menyalin toStringperilaku Java .
Konrad Rudolph

Mengapa bodoh daripada langsung menentukan operator << di kelas?
monksy

1
karena Anda tidak ingin memiliki loop tak terbatas dan crash
fnieto - Fernando Nieto

1
Mungkin teknik ini cepat dan mudah untuk melewatkan opsi tentang apa yang akan diserialisasi. Kalau tidak, akan diperlukan untuk menentukan operator teman kelas lain << yang diinisialisasi dengan opsi dan data untuk diserialisasi.
Samuel Danielson

Poin lain adalah bahwa implementasi fungsionalitas dump dapat ditegakkan oleh antarmuka, yang tidak akan mungkin menggunakan operator yang diusulkan.
jupp0r

29

Dalam C ++ 11, to_string akhirnya ditambahkan ke standar.

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


15
Ini adalah tambahan yang berguna untuk halaman ini, namun implementasi C ++ berbeda secara signifikan dengan yang ada di Java / C #. Dalam bahasa-bahasa tersebut, ToString()adalah fungsi virtual yang didefinisikan pada kelas dasar dari semua objek, dan karenanya digunakan sebagai cara standar untuk mengekspresikan representasi string dari objek apa pun. Fungsi-fungsi ini std::stringhanya berlaku untuk tipe bawaan. Cara idiomatis dalam C ++ adalah menimpa <<operator untuk tipe kustom.
Drew Noakes

9
"Keburukan" tanda tangan standar operator<<, dibandingkan dengan Stringsemantik sederhana Jawa mendorong saya untuk berkomentar, itu to_string()bukan hanya "tambahan yang berguna", tetapi cara baru yang disukai untuk melakukannya di C ++. Jika, seperti oleh OP, representasi string kustom dari sebuah kelas Adiinginkan, cukup tuliskan string to_string(A a)definisi class Asuffi di bawah ini . Ini menyebar dengan pewarisan seperti di Jawa, dan dapat dikombinasikan (dengan penambahan string) seperti di Jawa. Lagipula Non-override toString()di Jawa penggunaannya terbatas.
P Marecki

10

Sebagai perpanjangan dari apa yang dikatakan John, jika Anda ingin mengekstraksi representasi string dan menyimpannya di std::stringlakukan ini:

#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::stringstreamterletak di <sstream>tajuk.


2
Itu cara rumit konyol untuk mendapatkan string serialisasi!
Gerd Wagner

9

Pertanyaan telah dijawab Tetapi saya ingin menambahkan contoh konkret.

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

Contoh ini membutuhkan pemahaman operator yang berlebihan.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.