The following code compiles fine. However I wonder if it is legal C++. So more specific, if I have a const object, am I allowed to modify variables through pointers/referenc
It's legal, as const-ness of the class means that the class member is constant. a
is a pointer, so the address the pointer points to is constant, but the value stored at that address need not be.
Hence bar.a
is effectively an int * const
, not an int const *
.
As, after initialization, a reference cannot be made to refer to another entity anyway, it does not matter for bar.b
whether bar
is declared const
or not.
The constant variant of a pointer is a constant pointer, not a pointer to a constant. The constant variant of a reference is a reference, not a reference to a constant.
Small digression: You should be careful with references as members anyway in connection with const-ness, as the following will probably compile
struct Y { int m_a; };
struct X {
const Y & m_y;
X (const Y & y) : m_y (y) { }
};
Y y;
y.m_a = 1;
X x (y); // or const X x (y) -- does not matter
// X.m_y.m_a == 1
y.m_a = 2;
// now X.m_y.m_a == 2, although X.m_y is supposed to be const
As it is possible to assign a pointer to non-const to a pointer to const, you can build an analogous example with pointers. Remember that const
does only guarantee that YOU will not modify a variable via this very variable, it cannot guarantee that the contents of the variable are not modified at all.
I find the best way to think about const
in C++ is that it protects the physical bits of the object. It has no real protection for objects that it refers to. You can control the object definition with const
methods to provide deeper protection of values but by default C++ really only protects the physical object itself
One of the reasons why C++ allows you to modify the contents of a pointer through a const
value is that it really can't stop you. Imagine for a second that C++ disallowed that particular construct. You could trivially violate it by doing the following
size_t t1 = (size_t)bar.a; // legal
int* t2 = (int*)t1; // legal
*t2 = 3; // exactly the same as *bar.a = 3