Let's start with the obvious: some of this is platform and compiler dependent.
For starters, see this article on Explicit Type Conversion, and particularly:
A pointer to an object of a const
type can be cast into a pointer to a
non-const
type. The resulting pointer will refer to the original
object. An object of a const
type or a reference to an object of a
const
type can be cast into a reference to a non-const
type. The
resulting reference will refer to the original object. The result of
attempting to modify that object through such a pointer or reference
will either cause an addressing exception or be the same as if the
original pointer or reference had referred a non-const object. It is
implementation dependent whether the addressing exception occurs.
So this, explains why it may let you modify the variable without bitching.
Note that you could achieve the same using the cast operators directly, as that's what the compiler will do for you as explained in this article on cast operators, with their order of precedence given.
However, the real trick here is in the memory model. A statically allocated variable like a const int a may actually never have any "physical" location in memory, and is just replaced in place at compile time. (I'm trying to put my finger on the actual reference for this, but so far the closest and best I could grab was this (very nice) SO answer to is memory allocated for a static variable that is never used? - If anyone finds the actual reference, please let us know.)
So here the compiler is simply humoring you, and trying to make some sense of your pointer arithmetic as much as it can, but in the end substitutes a
actual values for the 2 last parts of your 2nd cout
call.