Alexmedkex
Alexmedkex

Reputation: 457

Overloaded operator, but still "no match for operator" error

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

Answers (2)

Ionut
Ionut

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

Serge Ballesta
Serge Ballesta

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

Related Questions