Int& 到 const int -static 与 dynamic-

Int& to const int -static vs dynamic-

class A
{ 
public:
  A(int i = 25) {x = i;y=new int[i];for(int j=0;j<i;j++) y[j]=j;}
  int& f() const {return x;}
  int& operator[](int i) const {return y[i];}

private:
  int x,*y;
};

int main()
{ 
   A a(15); 
   cout << a[5];
   cout << a.f();

   return 0;
}

当我试图编译它说的代码时

"Invalid initialization of reference of type int& from expression of type const int"

关于 f() 函数。

我明白了,因为它 returns 对函数声明为 const 的东西的非常量引用。但它不应该与 [] 重载的行为相同吗?

它还 returns 对函数声明为 const 的东西的非 const 引用,但它在那里没有显示错误。 有什么区别?

问题在这里:

int& f() const {return x;}

您的函数被标记为 const,因此它只能被 const 个实例调用。但是,您 return 是一个非 const 引用,因此如果有效,您可以使用它来修改 const 实例。编译器对此不满意。因此 f() 应该 return const int& 代替。

另一方面,int& operator[](int) const 编译,因为你 return 对指针成员 y 指向的数据的引用,但你不能修改指针本身。换句话说,在 const 实例上,指针 yconst,即 int * const y,但不是数据。因此按位 const-ness 被保留,但当然逻辑 const-ness 不是,但是编译器只关心按位 const-ness。

为了加强逻辑 const 的正确性,一种选择是编写两个版本的 operator[]:

const int& operator[](int i) const {return y[i];} 

int& operator[](int i) {return y[i];} 

请注意,第二个版本应标记为非 const,否则您将尝试重载两个仅在 return 类型上不同的函数。如果你想避免非const版本中的代码重复,你可以通过const_cast使用const版本,比如

int& operator[](int i) 
{
    return const_cast<int&>(const_cast<const A&>(*this)[i]); // use the const version
}

编辑

有人提议为类似指针的数据成员引入 const 传播包装器 propagate_const,这实际上也会使数据指向 const,请参见

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4057.pdf

它告诉您不能 return 从 const 成员函数中对数据成员的非 const 左值引用。你需要

const int& f() const {return x;}

如果需要,您可以决定提供非常量重载:

int& f() {return x;}

至于operator[],它没有return对数据成员的引用。您不能通过 operator[] 修改 xy,因此它实际上是一个 const 成员函数。您可以决定禁止 y 指向 的数据进行修改,如果您的 class 为数组建模,这将是有意义的。但这不是绝对必要的,编译器没有理由强制执行它。

const int& operator[](int i) const {return y[i];}
int& operator[](int i) {return y[i];}

在 C++ 语言中,class 的常量意味着其所有成员的直接常量(mutable 成员除外)。但是,class 的常量性不会传播到指针成员 指向的数据 或引用成员 引用的。 pointed/referenced 数据不是 class 的一部分,它的常量不受 class.

常量的影响

在您的示例中,将成员函数声明为 const 使其将成员 xy 视为 const。但是,y指向的数据并没有变成const,例如*yy[i] 都不是 const.

从封闭的 class 到 pointed/referenced 数据的常量传播实际上是用户意图的一部分。根据您要实现的内容,您需要或不需要它。语言完全由您决定(或图书馆级解决方案)。