I just found an interesting case: I passed an object by const reference
and still I was able to modify its member (which happens to be an lvalue reference
). Following is an example:
#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!
}
I used to think that if the parameter is passed by const ref
, then object is immutable but this doesn't appear to be the case here. Could someone please explain this? Thanks!
Note that in const
member function, the data member _name
itself will be considered as const
. This doesn't make any difference on _name
because it's a reference, which can't be const
-qualified. (In a sence the reference is always const
, you can't modify the reference itself, the reference can't be rebound to other object after initialization.)
On the other hand, the referenced object won't be become const
, so it's still possible to be modified, _name
won't become const std::string&
(reference to const
).
Similar thing happens on pointer members; in const
member function they become const
pointers, but not pointers to const
; you still could modify the pointed objects if they're non- const
s from the beginning.
Consider a different example.
Let's say you have struct A {int *x;};
.
When accessed through const A &ref
, x
would have type int *const
- a const
pointer to (non- const
) int
.
As you can see, const
is not added recursively to the pointer. It's only added at the top level.
Back to your code. Strictly speaking, const PersonRef& pr
is not a const
reference. It's a non- const
reference to const PersonRef
.
(In theory, a const
reference would be written as PersonRef &const pr
. But since references are not rebindable to begin with, adding const
wouldn't do anything, and thus isn't allowed. So technically references are never const
, even though you can't rebind them.)
The compiler can't add const
-ness to to std::string& _name
, since references can't be const
. And it doesn't add const
-ness recursively to the referenced type, simply because that's how the language works.
If you don't want this behavior, make std::string& _name
private
and add a pair of const
and non- const
accesors:
class PersonRef
{
std::string &_name;
public:
PersonRef(std::string& name_) : _name(name_) {}
std::string &name() {return _name;}
const std::string &name() const {return _name;}
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.