诠释和放大器;到const int -static vs dynamic-

时间:2015-05-31 12:36:43

标签: c++ dynamic reference const

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,但它没有显示错误。 有什么区别?

3 个答案:

答案 0 :(得分:2)

问题在于:

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[]的2个版本:

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

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

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

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

答案 1 :(得分:2)

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

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

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

int& f() {return x;}

对于operator[],它不会返回对数据成员的引用。您无法通过x修改yoperator[],因此它实际上是const成员函数。您可能决定不允许修改y指向的数据,如果您的类为数组建模,这将是有意义的。但它并非绝对必要,编译器没有理由强制执行它。

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

答案 2 :(得分:0)

在C ++语言中,类的constness意味着其所有成员的立即const(除了mutable个)。但是,类的常量不会传播到由引用成员引用的指针成员或指向的数据。指向/引用的数据不是类的一部分,它的常量不受类的常量的影响。

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

从封闭类到指向/引用数据的constness的传播实际上是用户意图的一部分。根据您尝试实施的内容,这是您需要或不需要的东西。该语言完全取决于您(或图书馆级解决方案)。