Search code examples
c++c++11constantsoverloadingostream

operator << overloading often fails if operator is const?


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.


Solution

  • 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;
    }