我刚刚发现一个有趣的情况:我通过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
传递,则对象是不可变的,但在这里似乎不是这种情况。有人可以解释一下吗?谢谢!
答案 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
指向(非{const
)int
的指针。
如您所见,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;}
};