繁体   English   中英

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

[英]Mutable Lvalue Reference of Parameter Passed by const Reference

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

#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传递的,则对象是不可变的,但在这里似乎并非如此。 有人可以解释一下吗? 谢谢!

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

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

指针成员也会发生类似的情况。 const成员函数,他们成为const指针,而不是指向const ; 如果指向对象从一开始就不是const则仍然可以对其进行修改。

考虑一个不同的例子。

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

如您所见, const 不会递归地添加到指针。 它仅在顶层添加。


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

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

编译器无法将const -ness添加到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;}

};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM