tul1
tul1

Reputation: 414

C++ operator [] overload not responding

I've created the class array and something is going weird.. the class is the following:

class array
{
    private:
        int *a_;
        size_t size_;
    public:
        array();
        array(const size_t);
        array(const arreglo &);
        ~array();
        int const &operator[](size_t)const;
        int &operator[](size_t);
        array const &operator=(const array&);
        bool empty()const;
};

The overload's implementation of [] are:

int const &array::operator[](size_t index)const
{
    std::cout << "getter" << std::endl; 
    return a_[index]; 
}
int & array::operator[](size_t index)
{
    std::cout << "setter" << std::endl; 
    return a_[index]; 
}

The way i'm testing the code is in this main:

int main()
{
    array a(7);
    a[0] = 3;
    a[1] = 6;
    a[2] = a[0] + a[1];
    array b = a;
    std::cout << b[2] << std::endl;
    return 0;
}

The problem is that the opertar [] is just using the getter version and prints through cout "setter" and never "getter". What is going wrong?

Upvotes: 1

Views: 153

Answers (2)

kfsone
kfsone

Reputation: 24249

Thinking of them as "getter" and "setter" variants is a mistake. The difference between the two is merely the cv-qualification of the function and the return type. They are both getters. More importantly, you are returning reference types.

References tend to decay, in this case to a mutable int, therefore the compiler is more likely to accept a non-const function call.

a[0];

The default evaluation of this statement is an integer value, not a reference, so that you can for instance do:

if (a[0])

and this is predicate on the value at a[0] rather than the reference (evaluating the reference would always be true and not very helpful).

Remember that when references are used in most statements they decay to the referred value.

int v = a[0]; // no error, even tho v's type is not int&
int& vr = a[0]; // decays to the value a references
                // then takes a reference of that

(Note: that the compiler may elide the implied set of operations to simply capture or imply the original reference in the second statement).

So the code

a[2] = a[0] + a[1]

It starts by getting the values from a[0] and a[1], knowing that it wants to do math, so the easiest way for it to do this is:

int a1 = a.operator[](1);
int a0 = a.operator[](0);
int& dest = a.operator[](2);
dest = a0 + a1;

If you want const, you're going to need either a const/const-ref to an array or to specify that you want a const ref:

const int& ar = a[0];

#include <iostream>

struct array
{
    int i = 0;
    array() {}
    const int &operator[](size_t) const { std::cout << "const int[]\n"; return i; }
    int &operator[](size_t) { std::cout << "int[]\n"; return i; }
};

int main()
{
    array a;
    a[0];
    int v1 = a[0];
    const int v2 = a[0];
    std::cout << "refs\n";
    int& v3 = a[0];
    const int& v4 = a[0];
    std::cout << "const array\n";
    const array b;
    b[0];
    int v5 = b[0];
    const int v6 = b[0];
    std::cout << "refs\n";
    //int& v7 = b[0]; // would produce a compile error
    const int& v8 = b[0];
}

See http://ideone.com/7EYGYj

Upvotes: 1

Captain Giraffe
Captain Giraffe

Reputation: 14705

In short

void f(const array& b){
     std::cout << b[2] << std::endl;
}

b is required to be const. All that is available is the const functions.

In your example it is a "read" but b is not const so the non-const is called. It is using the "setter" as the getter.

Upvotes: 0

Related Questions