Tôi muốn kiểm soát những gì được ghi vào một luồng, tức là cout
, cho một đối tượng của một lớp tùy chỉnh. Điều đó có khả thi trong C ++ không? Trong Java, bạn có thể ghi đè toString()
phương thức cho mục đích tương tự.
Tôi muốn kiểm soát những gì được ghi vào một luồng, tức là cout
, cho một đối tượng của một lớp tùy chỉnh. Điều đó có khả thi trong C ++ không? Trong Java, bạn có thể ghi đè toString()
phương thức cho mục đích tương tự.
Câu trả lời:
Trong C ++, bạn có thể quá tải operator<<
cho ostream
và lớp tùy chỉnh của mình:
class A {
public:
int i;
};
std::ostream& operator<<(std::ostream &strm, const A &a) {
return strm << "A(" << a.i << ")";
}
Bằng cách này, bạn có thể xuất các thể hiện của lớp trên luồng:
A x = ...;
std::cout << x << std::endl;
Trong trường hợp bạn operator<<
muốn in ra nội bộ của lớp A
và thực sự cần quyền truy cập vào các thành viên riêng tư và được bảo vệ, bạn cũng có thể khai báo nó như một chức năng kết bạn:
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 << ")";
}
friend
, và bên trong phần thân của lớp - với điều đó, bạn sẽ không phải làm gì using namespace
với không gian tên chứa toán tử (và lớp), nhưng ADL sẽ tìm thấy nó miễn là đối tượng của lớp đó một trong các toán hạng.
dump
phương pháp công khai đó là bẩn thỉu và không cần thiết. Sử dụng friend
ở đây là hoàn toàn tốt. Cho dù bạn thích một phương pháp dư thừa hay xâm nhập friend
hoàn toàn là vấn đề của hương vị, mặc dù friend
được cho là đã được giới thiệu cho mục đích chính xác này.
operator<<()
hàm thành viên sẽ không hoạt động: bạn sẽ phải biến nó thành hàm thành viên std::ostream
để chấp nhận toán hạng tay trái std::ostream
.
Bạn cũng có thể làm theo cách này, cho phép đa hình:
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); }
toString
hành vi của Java .
Trong C ++ 11, to_opes cuối cùng được thêm vào tiêu chuẩn.
ToString()
là một hàm ảo được định nghĩa trên lớp cơ sở của tất cả các đối tượng và do đó được sử dụng như một cách tiêu chuẩn để thể hiện biểu diễn chuỗi của bất kỳ đối tượng nào. Các chức năng trên std::string
chỉ áp dụng cho các loại tích hợp. Cách thành ngữ trong C ++ là ghi đè <<
toán tử cho các loại tùy chỉnh.
operator<<
, so với String
ngữ nghĩa đơn giản của Java nhắc tôi nhận xét, đó to_string()
không chỉ là "một bổ sung hữu ích", mà là cách ưa thích mới để làm điều đó trong C ++. Nếu, như OP, một đại diện chuỗi tùy chỉnh của một lớp A
là mong muốn, chỉ cần viết một string to_string(A a)
định nghĩa dưới đây là class A
đủ. Điều này lan truyền với sự kế thừa như trong Java và có thể được kết hợp (bằng cách thêm chuỗi) như trong Java. Non-overriden toString()
trong Java dù sao cũng được sử dụng hạn chế.
Như một phần mở rộng cho những gì John đã nói, nếu bạn muốn trích xuất biểu diễn chuỗi và lưu trữ nó trong một std::string
điều này:
#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
nằm trong <sstream>
tiêu đề.
Câu hỏi đã được trả lời. Nhưng tôi muốn thêm một ví dụ cụ thể.
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;
}
Ví dụ này đòi hỏi sự hiểu biết quá tải toán tử.