Chciałbym kontrolować, co jest zapisywane w strumieniu, tj. coutDla obiektu klasy niestandardowej. Czy to możliwe w C ++? W Javie można by nadpisać toString()metodę w podobnym celu.
Chciałbym kontrolować, co jest zapisywane w strumieniu, tj. coutDla obiektu klasy niestandardowej. Czy to możliwe w C ++? W Javie można by nadpisać toString()metodę w podobnym celu.
Odpowiedzi:
W C ++ możesz przeciążać operator<<dla ostreami swoją klasę niestandardową:
class A {
public:
int i;
};
std::ostream& operator<<(std::ostream &strm, const A &a) {
return strm << "A(" << a.i << ")";
}
W ten sposób możesz wyświetlać instancje swojej klasy w strumieniach:
A x = ...;
std::cout << x << std::endl;
Jeśli operator<<chcesz wydrukować wewnętrzne elementy klasy Ai naprawdę potrzebujesz dostępu do jej prywatnych i chronionych członków, możesz również zadeklarować to jako funkcję znajomego:
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, a także wewnątrz ciała klasy - dzięki temu nie będziesz musiał robić using namespacedla przestrzeni nazw zawierającej operator (i klasę), ale ADL znajdzie go tak długo, jak obiekt tej klasy jest jeden z operandów.
dumpmetoda publiczna jest brudna i niepotrzebna. Używanie friendtutaj jest całkowicie w porządku. To, czy wolisz metodę zbędną, czy natrętną, friendjest całkowicie kwestią gustu, chociaż friendprawdopodobnie została wprowadzona właśnie w tym celu.
operator<<()funkcji składowej nie zadziała: musiałbyś uczynić ją funkcją składową std::ostream, aby akceptowała operand typu po lewej stronie std::ostream.
Możesz to również zrobić w ten sposób, pozwalając na polimorfizm:
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); }
toStringzachowanie Javy .
W C ++ 11 to_string jest ostatecznie dodawane do standardu.
http://en.cppreference.com/w/cpp/string/basic_string/to_string
ToString()jest funkcją wirtualną zdefiniowaną w klasie bazowej wszystkich obiektów i dlatego jest używana jako standardowy sposób wyrażania reprezentacji ciągu dowolnego obiektu. Te funkcje std::stringmają zastosowanie tylko do typów wbudowanych. Idiomatycznym sposobem w C ++ jest przesłonięcie <<operatora dla typów niestandardowych.
operator<<, w porównaniu do prostej Stringsemantyki Javy, skłania mnie do uwagi, że to_string()jest to nie tylko „przydatny dodatek”, ale nowy preferowany sposób robienia tego w C ++. Jeśli, tak jak w przypadku OP, Apożądana jest niestandardowa reprezentacja klasy w postaci łańcucha , wystarczy napisać string to_string(A a)poniższą definicję class Awystarczającą. To propaguje się z dziedziczeniem, jak w Javie i może być łączone (przez dodawanie ciągów), jak w Javie. Brak zastępowania toString()w Javie i tak ma ograniczone zastosowanie.
Jako rozszerzenie tego, co powiedział John, jeśli chcesz wyodrębnić reprezentację ciągu i zapisać ją w pliku std::stringzrób to:
#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::stringstreamznajduje się w <sstream>nagłówku.
Odpowiedź na pytanie. Ale chciałem dodać konkretny przykład.
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;
}
Ten przykład wymaga zrozumienia przeciążenia operatora.