常量参考传递的参数的可变左值参考

时间:2019-09-15 09:12:44

标签: c++

我刚刚发现一个有趣的情况:我通过const reference传递了一个对象,但仍然可以修改其成员(恰好是lvalue reference)。 Following是一个示例:

#include <iostream>
#include <string>

struct PersonRef
{
  PersonRef(std::string& name_) : _name(name_) {}
  std::string& _name; // <==== IMPORTANT: it is a reference
};

void testRef(const PersonRef& pr) {
  std::string& name = pr._name; // binding to lvalue reference? How does it even compile?
  name = "changed!";
}

int main() {
  std::string name = "trivial_name";
  PersonRef pr{name};

  std::cout << pr._name << "\n"; // prints: trivial_name
  testRef(pr);
  std::cout << pr._name << "\n"; // prints: changed!
}

我曾经认为,如果参数由const ref传递,则对象是不可变的,但在这里似乎不是这种情况。有人可以解释一下吗?谢谢!

2 个答案:

答案 0 :(得分:1)

请注意,在const成员函数中,数据成员_name本身将被视为const。这对_name来说没有任何区别,因为它是一个引用,不能由const限定。 (在某种意义上,引用始终是 const ,您不能修改引用本身,引用不能在初始化后反弹到其他对象。 )

另一方面,引用的对象不会成为const,因此仍然可以对其进行修改,_name不会成为const std::string&(对{{1的引用}}。

指针成员发生类似的事情;在const成员函数中,它们成为const的指针,但不指向const的指针;如果指向对象从一开始就不是const,您仍然可以对其进行修改。

答案 1 :(得分:0)

请考虑其他示例。

假设您有struct A {int *x;};
通过const A &ref访问时,x的类型为int *const-const指向(非{constint的指针。

如您所见,const不是不是递归添加到指针。它只会添加到顶层。


返回您的代码。严格来说,const PersonRef& pr不是const引用。这是对 const的非const PersonRef引用。

(理论上,const引用将被写为PersonRef &const pr。但是由于引用不可重新绑定,因此添加const不会做任何事情,因此是'不允许。因此从技术上讲,即使您无法重新绑定引用,它们也永远不会const

编译器无法为const添加std::string& _name,因为引用不能为const。而且它不会递归地将const-ness添加到所引用的类型中,仅仅是因为这就是该语言的工作方式。


如果您不希望出现这种情况,请制作std::string& _name private并添加一对const和非const辅助对象:

class PersonRef
{
    std::string &_name;
  public:
    PersonRef(std::string& name_) : _name(name_) {}
    std::string &name() {return _name;}
    const std::string &name() const {return _name;}

};