Let us take this code as an example
#include <iostream>
using namespace std;
struct valStruct {
double& operator[](int i){return values[i];}; //line 6
double operator[](int i) const {return values[i];}; //line 7
double values[4];
};
int main () {
valStruct vals = {0,1,2,3};
cout << "Value before change" << endl;
for ( int i = 0; i < 3; i++ ) {
cout << "vals[" << i << "] = "<< vals[i] << endl;
}
vals[1] = 2.2; // change 2nd element
cout << "Value after change" << endl;
for ( int i = 0; i < 3; i++ ) {
cout << "vals[" << i << "] = "<< vals.values[i] << endl;
}
return 0;
}
I understand that line 6 (see comment in code) enables the writing (and reading!?) of a value to the index in array values
while line 7 only reads that value.
I understand the need of the const declaration in line 7 as preventing changing the value while not intended (although I do not understand how since line 6 exists), but my question is, why cannot I write the line as
double& operator[](int i) const {return values[i];}; //line 7
which throws out the error: binding reference of type ‘double&’ to ‘const double’ discards qualifiers
.
This also raises the question of why do we need line 7 at all since line 6 exists and can do both writing and reading.
EDIT:
I understand the idea of a const func() const [suggested here][1] and I do not understand how this answers my question. I did not understand the mechanism explained by the two answers given which answer my question.
I now understand that the second line is needed to deal with const objects of my function.
I also understand that when I have a func() const, it implicitly makes the members const. This means that the returned value needs to be constant and that is why this does not work ´double& operator[](int i) const { return values[i]; };´ while this does ´const double& operator[](int i) const { return values[i]; };´ [1]: Why use the keyword 'const' twice in a class member function C++
why do we need line 7 at all since line 6 exists and can do both writing and reading.
We need line 7 to work on const
objects. Line 6 can't be used on const
objects of type valStruct
. This is because const
class objects can only explicitly call const member functions, and the overloaded operator[]
in line 6 has not been marked as a const member function. So it can't be used on const object of type valStruct
. Thus, we need line 7 which "marks" the overloaded operator[]
as a const member function. More info about this can be found here.
Now, if you change the return type in line 7 to double&
, then the problem is that here you've overloaded operator[]
as a const member function. This means that the data members are also const
. And since we cannot bind an "lvalue reference to non-const object", to a const
object, we get the mentioned error. For example,
const double d = 43.4;
double& ref = d;//here we'll get the same error
The situation(of why you're getting the error) is similar to the above given snippet.
To solve(get rid of) this error, we need to change the return type from double&
to const double&
.