const引用传递的类的引用成员行为的设计原因

Design reasons for the behavior of reference members of classes passed by const reference

本文关键字:引用 成员 const      更新时间:2023-10-16

假设有代码

#include <iostream>
struct A{
  int y;
  int& x;
  A():y(0),x(y){}
};

void f(int& x){
  x++;
}
void g(const A& a){
  f(a.x);
  //f(a.y);
}

int main(){
  A a;
  g(a);
  std::cout<<a.y<<std::endl;
}

内部g()不允许对y调用f(),因为a是用const修饰符传递的然而,y的值可以在g()中通过对x调用f来修改;

有了指针,类似的东西可以得到非常相似的

struct B{
  int* x;  
}

g(const B&){
   *x++;
}

是允许的。这一点非常清楚:我们有一个指向非常量int的常量指针。但是在前面的引用示例中,如果引用是对象,为什么在这种情况下它们表现为指针?这种行为下的设计策略是什么?

如果引用是对象

引用是而不是对象——它们是对对象的引用。

你说得对,将引用本身设为const并不是很有用:因为它们是不可重新密封的,所以在任何情况下都不能像指针一样进行变异。

事实上,将引用视为具有特殊语法的const指针(而不是指向const的指针!)可能会更有帮助。

请注意,如果想要一个间接方法,它确实为引用对象提供常量(即,为了防止这里的f(a.x)调用),您可以编写一个智能指针样式的东西来实现它。


的具体示例

struct A
{
    int x;
    int *p;
    int &r;
    A() : x(0), p(&x), r(x) {}
};

现在处于A a:

  • a.x是可变int
  • a.p是指向可变int的可变指针(因此我们可以重新放置它)(我们可以更改它指向的整数的值)
  • 并且a.r是对可变int的引用
    • 请注意,由于我们无论如何都不能更改(重新设置)引用,因此引用本身是常量或可变的并不意味着什么

但在const A b:中

  • b.x是一个常量整数
  • b.p是一个指向可变int的常量指针(因此我们无法重新定位它)
  • b.r是对可变int的引用
    • 注意constness是如何应用于A的成员(指针或引用)的,并且按比例传递到引用

标准中的实际语言是

c++11

8.3.2参考文献[dcl.ref]

1-[…][注:引用可以被认为是对象的名称。--尾注]

因此,如果引用是一个对象的名称,而不是对象本身,那么使封闭结构为const会使名称为const(这毫无意义,因为引用不能反弹),但不是对象本身。

我们也看到

6-如果typedef、类型模板参数或decltype说明符表示类型TR即对类型T的引用,尝试创建类型"对cvTR的左值引用"会创建类型"T的左值参考"[…]

由于对cv对象的成员访问会创建cv左值,因此同样适用,cv资格将被取消。

在C++中,引用通常由指针实现。(我认为sizeofa引用和指针是相同的)。

事实上,我通常认为引用是指针,但语法不同。