Consider the following example:
#include <iostream>
class A {
const int i;
const int j;
public:
A(int i_, int j_) : i(i_), j(j_) {}
std::ostream& operator<<(std::ostream& o) const {
o << "i is " << i << ", j is " << j;
return o;
}
};
std::ostream& operator<<(std::ostream& o, const A& a ) {
o << "This is A: ";
a.operator<<(o);
return o;
}
int main() {
A a(0,42);
std::cout << a << std::endl;
return 0;
}
It will generate the following output:
This is A: i is 0, j is 42
The output is correct but I don't like how I am calling A's original operator<<.
I am trying to figure out how to properly define that operator, so it could be called this way:
o << "This is A: " << (some magic)a;
instead of
o << "This is A: ";
a.operator<<(o);
I have tried various ways but either I get to ambiguity issues or getting an address of the std::cout and broken string. Notice that the result std::ostream& of A::operator<< is a remnant of my tests. In the example above it would suffice to use void.
Is it possible without creating an intermediate class B that derives from class A and defines its own operator<< (class NiceOutputOfA : public A {...};) ?
Binary operators defined in-class always have the class as the left-hand side operand. Which means you cannot implement stream insertion/extraction in-class.
Probably the most common way is to implement the operator as a friend defined inline in the class.
Another reasonably common way is to provide a named streaming function in the class, and an out-of-class streaming operator which calls that function. You almost did that, but named that function operator <<.
The closest resolution I came to is by creating an intermediate class:
class Decorate {
const A& a;
public:
Decorate(const A& a_) : a(a_) {}
friend std::ostream& operator<<(std::ostream& o, const PrintA& pa) {
o << "This is A: " << pa.a;
return o;
}
};
and having it printed this way:
int main() {
A a(0,42);
std::cout << Decorate(a) << std::endl;
return 0;
}
I was looking for something prettier but based on Angew's answer I lost hope to have it done suing proper operator<< declaration.
Thanks for all your help!
Marking Angew's response as the answer.
Related
This question stems from a larger code I am working on but hopefully I can break it down to simplify:
Say I have two classes, one which holds 2 integer variables, and another which contains a vector that holds the first class
class TwoInts {
int num1;
int num2;
}
class NumHold {
std::vector<TwoInts> numVector;
}
How would I go about printing my numHold class exactly? I know I would have to provide an overloaded stream operator
std::ostream &operator<< (std::ostream &out, const NumHold &myNumHold){;}
But I'm a little confused as to the syntax regarding how I would print out these integers from the vector. I also understand that in order for the stream operator to work I would have to add it to my class as a friend, I just wanted to keep my NumHold class as simplified as possible for the examples sake. Hopefully this was clear enough of an explanation, any help is appreciated
Treat out how you would treat std::cout, then return it at the end of the function:
std::ostream& operator<<(std::ostream& out, const NumHold &myNumHold){
//one possible output format
for(const auto& twoInt : myNumHold.numVector){
out << twoInt.num1 << ", " << twoInt.num2 << '\n'; //pretend out is std::cout
}
return out; //don't forget to return it at the end
}
If appropriate, declare the overload as a friend function within the NumHold class:
#include<iostream>
class NumHold {
private:
std::vector<TwoInts> numVector;
public:
//friend operator overload declaration
friend std::ostream& operator<<(std::ostream& out, const NumHold& myNumHold);
};
In your example, it is appropriate, as the overload function accesses private variables.
You need to be able to access the members of each TwoInts in order to print them. One way to do this is to make them public.
class TwoInts {
public: //lets NumHold access variables to print
int num1;
int num2;
};
class NumHold {
public:
std::vector<TwoInts> numVector;
friend std::ostream& operator << (std::ostream& out, const NumHold& myNumHold) {
for (const TwoInts& ti : myNumHold.numVector) {
out << "(" << ti.num1 << ", " << ti.num2 << ")" << std::endl;
}
return out;
}
};
You can also consider adding printing methods to your classes:
#include<iostream>
class TwoInts {
private:
int num1;
int num2;
public:
void printnum1(){
std::cout << num1;
}
void printnum2(){
std::cout << num2;
}
}
class NumHold {
private:
std::vector<TwoInts> numVector;
public:
//this function prints the private attributes of the class
void printnumVector(){
for (int i = 0; i < numVector.size(); i++){
std::cout << numVector[i].printnum1() << " " << numVector[i].printnum2() << std::endl;
}
}
};
I'm having troubles understanding the reason why the compiler accuses error, when the return type of a << operator overload is std::string. Could you please help me understand?
Bellow is an reproducible example, which gives a gigantic error.
class XY
{
int X__;
int Y__;
public:
XY(int x, int y):X__(x), Y__(y){}
~XY(){}
std::string operator<<(const XY_cartesiano& c)
{
std::stringstream ss;
ss << "{ " << X__ << ", " << Y__ << " }";
return ss.str();
}
int x() const{return X__;}
int y() const{return Y__;}
};
void main()
{
XY a(1,2);
std::cout << a;
}
Let's take something like this as an example:
cout << "My number is " << 137 << " and I like it a lot." << endl;
This gets parsed as
((((cout << "My number is ") << 137) << " and I like it a lot.") << endl);
In particular, notice that the expression cout << "My number is " has to evaluate to something so that when we then try inserting 137 with << 137 the meaning is "take 137 and send it to cout."
Imagine if cout << "My number is " were to return a string. In that case, the << 137 bit would try to use the << operator between a string on the left-hand side and an int on the right-hand side, which isn't well-defined in C++.
The convention is to have the stream insertion operator operator << return a reference to whatever the left-hand side stream is so that these operations chain well. That way, the thing on the left-hand side of << 137 ends up being cout itself, so the above code ends up essentially being a series of chained calls to insert things into cout. The signature of these functions therefore usually look like this:
ostream& operator<< (ostream& out, const ObjectType& myObject) {
// ... do something to insert myObject into out ... //
return out;
}
Now, everything chains properly. Notice that this function is a free function, not a member function, and that the left-hand side is of type ostream and the right-hand side has the type of your class in it. This is the conventional way to do this, since if you try overloading operator << as a member function, the left-hand side will be an operand of your class type, which is backwards from how stream insertion is supposed to work. If you need to specifically access private fields of your class in the course of implementing this function, make it a friend:
class XY {
public:
...
friend ostream& operator<< (ostream& out, const XY& myXY);
};
ostream& operator<< (ostream& out, const XY &myXY) {
...
return out;
}
Correct way to overload << operator in your case is
ostream& operator<<(ostream& os, const XY& c)
{
os << c.X__ <<" "<< c.Y__ ;
return os;
}
You have overloaded operator<< in a way that's incompatible with the conventions you must follow when you intend to use the operator with a std::ostream object like std::cout.
In fact, your operator<<'s signature has nothing to do with streams at all! It is just a member function of XY which takes another XY (which it then does not use), returns a string and has an unsual name. Here's how you would theoretically call it:
XY a(1,2);
XY b(1,2);
std::string x = (a << b);
The correct way to overload operator<< for use with streams is to make the operator a non-member function, add a stream reference parameter and return a stream reference to the stream argument. You also do not need a string stream; you write directly to the stream you get:
#include <iostream>
class XY
{
int x;
int y;
public:
XY(int x, int y) : x(x), y(y) {}
int X() const { return x; }
int Y() const { return y; }
};
std::ostream& operator<<(std::ostream& os, XY const& c)
{
os << "{ " << c.X() << ", " << c.Y() << " }";
return os;
}
int main()
{
XY a(1,2);
std::cout << a;
}
If I want to overload the << operator to use cout on a class, it should look like this:
template <typename coutT>
friend ostream& operator << (ostream &, const vector3D<coutT>&);
inside the class, and
template <typename coutT>
ostream& operator << (ostream & os,const vector3D<coutT>& v)
{
os << "x: " << v.x<< " y: " << v.y << " z: " << v.z;
return os;
}
on the outside. Please take note of the const at the second operand.
This sample of code works just fine. Now to the problem.
If I were to write the overload function using the getters for the fields, instead of addressing them directly (since operator<< is a friend), my compiler would throw an error:
template <typename coutT>
ostream& operator << (ostream & os,const vector3D<coutT>& v)
{
os << "x: " << v.getX() << " y: " << v.getY() << " z: " << v.getZ();
return os;
}
The error:
(VisualStudio2012) errorC2662: "this-pointer cannot be converted from "const vector3D" in "vector3D&""
An important note is that deleting the "const" at the second operand so that it's like
ostream& operator << (ostream & os,vector3D<coutT>& v){...}
ended compiler errors, but since I don't want to change v, it should really be a const.
I should also mention that I think it may have to do with method calls in general, but I'm not sure.
edit:
So it is solved, declaring functions as const sticks to const-correctness.
The error message explains it in the way that it cannot cast the const type to a non-const one.
btw.: I'm actually impressed about the quick responses.
The getter function should be declared const if you want to use it that way.
For example
int getValue() const {
return x;
}
Complete example:
#include <iostream>
#include <vector>
using namespace std;
class Foo {
int x;
public:
Foo(int a) : x(a) {
}
int getValue() const {
return x;
}
friend ostream & operator<<(ostream & out, const Foo & foo) {
return out << foo.getValue();
}
};
int main() {
vector<Foo> foo_vec = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (vector<Foo>::iterator it = foo_vec.begin(); it != foo_vec.end(); it++) {
cout << *it << ", ";
}
return 0;
}
Your problem is that you didn't mark the get functions const:
They need to look like this:
double getX() const;
You need to make the accessor functions const:
struct V
{
int getX() const { /* ... */ }
^^^^^
};
Only const member functions can be invoked on constant object values. In turn, const member functions cannot mutate the object. Thus const-correctness guarantees that a constant value cannot be mutated by invoking any of its member functions.
I have a class A, for which I have defined an (overloaded) stream insertion operator. I publicly derive a class B from this class A, which has an additional data member. Therefore I'll need to redefine the overloaded stream insertion operator for the derived class and I've do it this way:
#include <iostream>
using namespace std;
class A {
int i;
char c;
public:
A(int i = 0, char c = ' ') {
this->i = i;
this->c = c;
}
friend ostream& operator << (ostream&, const A&);
};
class B : public A {
double d;
public:
B(int i = 0, char c = ' ', double d = 0.0) : A(i, c), d(d) {}
friend ostream& operator << (ostream&, const B&);
};
ostream& operator << (ostream& out, const A& a) {
out << "\nInteger: " << a.i << "\nCharacter: " << a.c << endl;
return out;
}
ostream& operator << (ostream& out, const B& b) {
out << b;
out << "\nDouble: " << b.d << endl;
return out;
}
int main() {
A a(10, 'x');
B b(20, 'y', 5.23);
cout << b;
return 0;
}
Question-1: Is this an appropriate technique of doing so? If not, kindly let me know where I'm going wrong.
Question-2: On running, this program crashes. Why so?
One common way to support this is to have the overloaded operator invoke a virtual member function:
class A {
public:
virtual std::ostream &write(std::ostream &os) const {
// write self to os
os << "A\n";
return os;
}
};
class B : public A {
public:
virtual std::ostream &write(std::ostream &os) const {
// write self to os
// This can use the base class writer like:
A::write(os);
os << "B\n";
return os;
}
};
Then the operator overload just invokes that member function:
std::ostream &operator<<(std::ostream &os, A const &a) {
return a.write(os);
}
Since write is virtual and you're passing the A by (const) reference, this invokes the correct member function based on the actual type (i.e., A::write if the object is really an instance of A, and B::write if it's an instance of B).
For example, we could exercise these something like this:
int main() {
A a;
B b;
std::cout << a << "\n";
std::cout << b << "\n";
}
...which produces output like this:
A
A
B
In real use, you probably want to make the write functions protected, and make the operator<< a friend of A.
The program crashes because your second insertion operator calls itself:
ostream& operator << (ostream& out, const B& b) {
out << b; // <--YIKES!
out << "\nDouble: " << b.d << endl;
return out;
}
Generally this is a good approach, although I prefer to give the classes a public virtual print(ostream&) const function, and have the insertion operator call that.
I'm writing a method to print some spaces in std::cout, I know there are other ways using the standard library to achieve the same objective. Anyway, I used a typedef to store the number of spaces and an overloading of the << operator. But my overloading isn't called at all because my typedef is interpreted as an unsigned int.
So how can I tell to the compiler to call my function instead ?
class MyClass {
private:
typedef unsigned int space_type;
public:
std::ostream& operator<< (std::ostream& _os, space_type _n_spaces) {
for (int _C = 0; _C < _n_spaces; _C++)
_os << " ";
return _os;
}
void PrintNumbers(char _a, char _b) {
space_type spaces = 5;
std::cout << _a << spaces << _b << std::endl;
}
}
int main () {
MyClass class_instance;
class_instance.PrintNumbers('K', 'X');
std::cin.get();
return 0;
}
This is the expected output:
K X
This is the output I obtain:
K5X // 5 is interpreted as an unsigned int, so my overloaded function
// isn't called, instead is called the std overloading with unsigned int
Typedef doesn't create new type, it just creates alias of existing type. Possbile you could use something like this:
struct SpaceType {
int space_cnt;
};
...
std::ostream& operator<< (std::ostream& _os, SpaceType _n_spaces) {
for (int _C = 0; _C < _n_spaces.space_cnt; _C++)
_os << " ";
return _os;
}
...
SpaceType spaces = { 5 };
std::cout << _a << spaces << _b << std::endl;
Since you're defining space_type as an alias (i.e. typedef) and not a type, it is not distinguishable from int, and the compiler will issue an error if you attempted to overload operator(std::ostream&, int).
But what you're doing is defining a class member:
std::ostream& operator<< (std::ostream& _os, space_type _n_spaces)
When you define operators as class members, the first argument to the operator is (implicitly) an instance of the class. So in principle, that could only be called with:
MyClass m;
m << ???
But here is a problem: an operator function called using infix notation can only have two parameters, and in the case of a member operator function, the first argument is implicit. m << x can only be implemented by MyClass::operator<<(decltype(x)).
In short, you can only implement this with a non-member operator<< and the second argument to that overload must be a user type. So the following will work fine:
struct space_t {
unsigned x;
space_t(unsigned x) : x(x) {}
operator unsigned() const { return x; }
};
std::ostream& operator<< (std::ostream& os, space_t n) {
for (unsigned i = 0; i < n; ++i) os << " ";
return os;
}
See it on ideeone