Reputation: 457
I have a class that overloads the output operator "<<", and I have implemented it as such. However, the compiled complains about "no match for operator <<.." in the main method. I have no idea why it's not working.
/*
* Accumulator.cpp
*
*
*
*/
#include <iostream>
#include "Accumulator.h"
using namespace std;
Accumulator::~Accumulator() {
// TODO Auto-generated destructor stub
}
void Accumulator::operator+=(const int nbr) {
nbrs.push_back(nbr);
}
void Accumulator::undo() {
if (!comitted) {
nbrs.pop_back();
}
}
void Accumulator::commit() {
lastCommit = nbrs;
comitted = true;
}
void Accumulator::rollback() {
nbrs = lastCommit;
}
ostream& Accumulator::operator<<(ostream &out, const Accumulator &accum){
int sum = 0;
for(int nbr : nbrs){
sum+= nbr;
}
out << sum;
return out;
}
int main() {
Accumulator accum;
char cmd;
while (cin >> cmd) {
switch (cmd) {
case 'p':
cout << "Sum is now " << accum << endl;
break;
case 'a': {
int nbr;
cin >> nbr;
accum += nbr;
break;
}
case 'u':
accum.undo();
break;
case 'c':
accum.commit();
break;
case 'r':
accum.rollback();
break;
}
}
}
Upvotes: 2
Views: 3964
Reputation: 6876
Non-static member functions always have an extra hidden parameter, which is the this
pointer, the object on which the function is called. So lets say you have a class like this:
class Test {
public:
void f(int param) {
}
};
Test t;
t.f(10);
The call t.f(10)
is basically equivalent to something like this in the background: Test::f(&t, 10)
(note that this is not valid code, it's just to give you an idea of what happens).
Now going back to your operator, if you make it a member function in your class, then you can't call it as you normally would. That is because calling it like this:
std::cout << accum;
is equivalent to this:
cout.operator<<(accum);
which in the background is equivalent to this:
Accumulator::operator<<(&cout, accum);
while your member function is equivalent to this:
ostream& operator<<(Accumulator* this, ostream &out, const Accumulator &accum);
Notice that the parameters don't match.
So the only way to correctly overload operator<<
is to make it a free function:
class Accumulator {...};
ostream& operator<<(ostream &out, const Accumulator &accum);
This way, a normal call like this:
std::cout << accum;
is equivalent to this:
operator<<(std::cout, accum);
which matches exactly the declaration of the overload.
If in your overload implementation you need to access private members of your Accumulator
class, you can do it in different ways: make your overload a friend of the class for example, or add a public function in your class like this:
class Accumulator {
public:
void printToStream(ostream &out) const {
out << private_members;
}
};
and call it from your operator overload like this:
ostream& operator<<(ostream &out, const Accumulator &accum) {
accum.printToStream(out);
return out;
}
Now you don't have to make the overload a friend of the class anymore.
Upvotes: 2
Reputation: 149155
As suggested by @n.m. , the stream injectors must not be overloaded as member function but as 2 parameters plain functions.
Your .h file becomes:
class Accumulator {
... // no operator << here !
};
ostream& operator << (ostream &out, const Accumulator& accum);
and implementation:
ostream& operator << (ostream &out, const Accumulator& accum) {
...
return out;
}
You would only use the one parameter member function overload, if you were writing a custom ostream
class (say a specialized logger for example).
Upvotes: 0