[英]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- const
) int
的const
指针。
如您所见, 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.