2

Take a look at this simple array class

class Array {
    const unsigned int _size;
    int _array[100];

public:
    Array() : _size(100) {
        for(unsigned int i = 0; i < _size; i++)
            _array[i] = 0;
    }

    int& operator[](unsigned int index) {
        cout << "normal operator[].\n";
        return _array[index];
    }

    const int& operator[](unsigned int index) const {
        cout << "const operator[].\n";
        return _array[index];
    }
};

int main()
{
    Array a;

    a[3] = 1;
    cout << a[3] << "\n";

    system("pause");
    return 0;
}

The "normal operator[]" line is executed twice, though I would expect the second call (cout << a[3] << "\n";) to be using the const version of the overloaded operator, because it doesn't change the array itself.

Why is that? Is there a way to force the const version to be called as I wish?

McLovin
  • 3,295
  • 7
  • 32
  • 67
  • 1
    `a` isn't `const` in that expression, so the const overload isn't called. If you want to force it you can use `const_cast(a)[3]` but it really isn't necessary. – user657267 Oct 21 '15 at 00:02
  • What's the point then? I'm trying to mimic std::vector as it also has two overloaded operator[] functions. Are you saying that unless the std::vector object is const (as I see no point in that), the non-const version will always be called? – McLovin Oct 21 '15 at 00:05
  • 3
    `unless the std::vector object is const the non-const version will always be called` this is (sort of) the definition of a `const` overload, yes. Note that the underlying object itself might be non-const and is being accessed through a const reference, which is usually the case. In your code for instance you could also use `Array const& b = a; cout << b[3];` – user657267 Oct 21 '15 at 00:07
  • Possible duplicate of [Const and Non-Const Operator Overloading](http://stackoverflow.com/questions/19237411/const-and-non-const-operator-overloading) – user657267 Oct 21 '15 at 00:12
  • That makes sense now. Thanks! – McLovin Oct 21 '15 at 00:16
  • `system(pause)`... you know you can tell your IDE to not auto-close console windows, right? – casey Oct 21 '15 at 01:02
  • I prefer that line though. @casey – McLovin Oct 21 '15 at 18:02

2 Answers2

1

When you have an overloaded const version of a method, the const version will be called when the object is const. For example:

#include <iostream>
using namespace std;

class MyClass
{
public:

    void foo()
    {
        cout << "foo()" << endl;
    }

    void foo() const
    {
        cout << "foo() const" << endl;
    }
};

int main()
{
    MyClass a;
    const MyClass b;

    a.foo();
    b.foo();

    return 0;
}

will call the normal foo() for the object a, and the const version for the object b.

In your case, you just have to avoid trying to assign to the const version. For example:

Array a;
const Array b;

a[3] = 1;
// b[3] = 1; // error
cout << a[3] << "\n";
cout << b[3] << "\n";

works fine. But if you try to make the assignment to b, you get a compile error.

Monfico
  • 154
  • 7
0

std::ostream &operator<<(int x) doesn't take its parameter as const (because const isn't useful when passing by value), so the non-const operator[] can be called.

So, when will const operator[] be called?

It is true that a const vector variable declaration is almost always useless aside from some edge cases. The primary reason const operator[] is important, and the most often you will see it used, is calling it on a reference parameter.

int readStuff(const std::vector<int> &dontMutateMe) {
    return dontMutateMe[42]; // const
}

Constant reference parameters are valuable, and this code wouldn't work without const operator[].

Community
  • 1
  • 1
pmttavara
  • 698
  • 7
  • 16
  • `std::ostream& operator<<`'s parameter declaration has nothing to do with the overload selected for `a`, the non-`const` `operator[]` would still be called if it were declared `int const& x`. – user657267 Oct 21 '15 at 00:24