Int& to const int -static vs dynamic-

Int& to const int -static vs dynamic-

本文关键字:-static vs dynamic- int const to Int      更新时间:2023-10-16
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()函数。

我理解它,因为它返回一个非const引用,指向函数声明为const的东西。但它的行为不应该与[]重载相同吗?

它还返回一个非const引用,指向函数声明为const的对象,但没有显示错误。有什么区别?

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

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

如果需要,可以决定提供非const重载:

int& f() {return x;}

对于operator[],它不返回对数据成员的引用。不能通过operator[]修改xy,所以它实际上是const成员函数。您可以决定不允许修改y指向的数据,如果您的类建模一个数组,这将是有意义的。但这并不是严格必需的,编译器也没有理由强制执行它。

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

问题就在这里:

int& f() const {return x;}

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

另一方面,int& operator[](int) const编译,因为您返回对指针成员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,否则你会试图重载两个函数,它们只是返回类型不同。如果你想在非const版本中避免代码重复,你可以通过const_cast使用const版本,如

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

编辑

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

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

在c++语言中,类的constness意味着其所有成员的直接constness (mutable成员除外)。然而,类的constness不会传播到指针成员所指向的数据或引用成员所引用的数据。指向/引用的数据不是类的一部分,它的constness不受类的constness的影响。

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

从封闭类到指向/引用数据的constness传播实际上是用户意图的一部分。这是你需要或不需要的东西,这取决于你想要实现什么。该语言将其完全交给您(或库级解决方案)。