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กับ namespace ที่มีโอเปอเรเตอร์ (และคลาส) แต่ ADL จะค้นหามันตราบเท่าที่วัตถุของคลาสนั้น หนึ่งในตัวถูกดำเนินการ
Pavel Minaev

... ข้างต้นตั้งใจจะพูดว่า " นิยามว่ามันเป็นเพื่อนภายในร่างของชั้นเรียน" - ในขณะที่คำจำกัดความของสมาชิกแบบอินไลน์
Pavel Minaev

2
@fnieto: dumpวิธีสาธารณะนั้นสกปรกและไม่จำเป็น ใช้friendที่นี่ดีอย่างสมบูรณ์ ไม่ว่าคุณจะชอบวิธีการที่ซ้ำซ้อนหรือการล่วงล้ำfriendนั้นเป็นเรื่องของรสนิยมอย่างสิ้นเชิงแม้ว่าจะfriendได้รับการแนะนำเพื่อวัตถุประสงค์ที่แน่นอนนี้ก็ตาม
Konrad Rudolph

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
Konrad Rudolph

ทำไมโง่กว่าระบุโอเปอเรเตอร์ << ในชั้นเรียนโดยตรง
พระสงฆ์

1
เพราะคุณไม่ต้องการที่จะมีวงที่ไม่มีที่สิ้นสุดและพัง
fnieto - Fernando Nieto

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 ++ คือการแทนที่<<ผู้ประกอบการสำหรับประเภทที่กำหนดเอง
Drew Noakes

9
"ความอัปลักษณ์" ของลายเซ็นมาตรฐานของoperator<<เมื่อเทียบกับซีแมนทิกส์ง่ายๆ Stringของ Java แจ้งให้ฉันสังเกตว่าto_string()ไม่เพียง แต่ "การเพิ่มที่มีประโยชน์" แต่เป็นวิธีที่นิยมใช้ใน C ++ ถ้าเช่นเดียวกับ OP ต้องการการแทนค่าสตริงแบบกำหนดเองของคลาสAเพียงแค่เขียนstring to_string(A a)คำจำกัดความด้านล่างของความclass Aเพียงพอ สิ่งนี้แพร่กระจายด้วยการสืบทอดใน Java และสามารถรวมกัน (โดยการเพิ่มสตริง) เช่นเดียวกับใน Java ไม่ใช่ overriden 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
นั่นเป็นวิธีที่ยุ่งยากสำหรับการรับสตริงการทำให้เป็นอนุกรม!
Gerd Wagner

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

ตัวอย่างนี้ต้องการการทำความเข้าใจกับตัวดำเนินการโอเวอร์โหลด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.