为什么在重载 [] 运算符时无法 return const 引用

Why is it not possible to return a const reference while overloading the [] operator

我们以这段代码为例

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

我知道第 6 行(请参阅代码中的注释)允许将值写入(和读取!?)数组 values 中的索引,而第 7 行仅读取该值。

我理解第 7 行中 const 声明的必要性,因为它可以防止在无意的情况下更改值(尽管我不明白自第 6 行以来如何存在),但我的问题是,为什么我不能将此行写为

double& operator[](int i) const {return values[i];}; //line 7

抛出错误:binding reference of type ‘double&’ to ‘const double’ discards qualifiers.

这也提出了一个问题,为什么我们需要第 7 行,因为第 6 行存在并且可以写和读。

编辑:

我理解 const func() const [在此处建议][1] 的概念,但我不明白这如何回答我的问题。我不明白回答我问题的两个答案所解释的机制。

我现在明白了,第二行是处理我函数的常量对象所需要的。

我也明白当我有一个 func() const 时,它隐含地使成员成为 const。这意味着 returned 值需要保持不变,这就是为什么这不起作用 ´double& operator[](int i) const { return values[i]; };´ 虽然这样做 ´const double& operator[](int i) const { return values[i]; };´ [1]:

why do we need line 7 at all since line 6 exists and can do both writing and reading.

我们需要第 7 行来处理 const 个对象。第 6 行不能用于 const 类型 valStruct 的对象。这是因为constclass对象只能显式调用const成员函数,而第6行重载的operator[]没有被标记为const成员函数。所以它不能用在 valStruct 类型的 const 对象上。因此,我们需要第 7 行将重载的 operator[] “标记”为 const 成员函数。有关此的更多信息,请参见 here.


现在,如果您将第 7 行中的 return 类型更改为 double&,那么问题是您在这里将 operator[] 重载为 const成员函数。这意味着数据成员也是const。并且由于我们无法将 "lvalue reference to non-const object" 绑定到 const 对象,所以我们得到了上述错误。例如,

const double d = 43.4;
double& ref = d;//here we'll get the same error

情况(您收到错误的原因)与上面给定的代码段类似。

要解决(摆脱)这个错误,我们需要将 return 类型从 double& 更改为 const double&

this 引用 const 合格成员函数中的 const 对象。这里:

double& operator[](int i) const {return values[i];}; //line 7

您正在尝试 return 对 this->values[i]; 的引用。当对象是 const.

时,该引用不能是 non-const

通常提供两个重载:

double& operator[](int i) { return values[i]; };              // 1
const double& operator[](int i) const { return values[i]; };  // 2
// ^ returned reference is const 
//                                ^ current object is const

第一个只能在 non-constant 对象上调用。当对象为 const 时,则调用第二个:

valStruct a;
double x = a[0];  // calls 1
const valStruct b;
double x = b[0];  // calls 2

因为复制 double 并不昂贵,您可以 return double 而不是参考。

This also raises the question of why do we need line 7

因为没有 const operator[] 你将无法调用 b[].