Visual walkthrough — const correctness — const variables, const pointers, const member functions
Before any C++ appears, agree on three drawings we'll reuse the whole page:
- A box = a slot of memory that holds a value.
- A green box = writing is allowed through this name.
- A red box = writing is blocked through this name (read-only).
That's the entire vocabulary. Let's go.
Step 1 — A variable is a named box; const paints it red
WHAT. A plain variable is a box you can read and write. Writing const in front of it repaints the box red: reads still work, writes are rejected by the compiler.
WHY. The word const is a promise — "I will not write through this name." The compiler is not being polite; it enforces the promise. This costs nothing at runtime because the check happens while compiling, before the program ever runs.
PICTURE. Look at figure s01. On the left, int a = 10 — a green box, the two arrows (read ↑, write ↓) both allowed. On the right, const int max = 100 — the same box, painted red; the write arrow is crossed out.

This "left first, else right" reading is the single rule that runs the whole next section. Hold onto it.
Step 2 — A pointer is a second box that stores an address
WHAT. A pointer is itself a box. It doesn't hold a number like 10; it holds the address (the location) of another box. When you write *p, you follow the arrow and land on the box it points at.
WHY. With pointers there are now two boxes in play — the pointer box and the box it points to — so there are two independent things const could lock. Confusion comes from not knowing which one got painted. Figure s02 separates them so we never mix them up.
PICTURE. In s02, the yellow box on the left is p (holds an address). The arrow leads to the blue box a (holds 10). Notice the two verbs you can do:
- change
p→ make the arrow point somewhere else (repoint); - change
*p→ write into the box the arrow lands on (write-through).

Step 3 — const int* p: the pointee is red, the pointer is green
WHAT. Write const on the left of the *. By our Step-1 rule ("applies to the thing on its left"), const paints the int — the box the arrow lands on. The pointer box stays green.
WHY. This is the most useful shape in all of C++: "I hold a handle to your data, I can read it, I will not write it — but I'm free to point my handle elsewhere." That's exactly what a read-only function parameter wants.
PICTURE. In s03 the arrow's target box is red (crossed-out write), while the pointer box itself is green — the arrow is allowed to swing to a new box.

This is the shape used by void print(const char* s) — see Function parameters — pass by value vs const reference.
Step 4 — int* const p: the pointer is red, the pointee is green
WHAT. Move const to the right of the *. Now, by the same rule, const paints the thing on its left — which is p, the pointer box. The pointer is locked to one address forever; the target box stays green and writable.
WHY. Sometimes you want "this handle must always point at this one object — but I'm allowed to edit that object." A locked handle to a live box.
PICTURE. s04 is the mirror image of s03: now the pointer box is red (its arrow is frozen, glued to a), while the target box is green (write-through allowed).

Notice the callback to Step 1: since p itself is now const, it must be initialized at declaration.
Step 5 — const int* const p: paint both boxes red
WHAT. Put const on both sides of the *. Left const paints the target; right const paints the pointer. Nothing moves, nothing gets written.
WHY. Total lockdown — a permanent read-only view of one fixed object. Rare, but it's just Steps 3 and 4 stacked, so it costs no new thinking.
PICTURE. s05: both boxes red. The arrow is frozen and the target is unwritable.

The three pointer shapes are now a single idea seen three ways: which box is red?
const int* p
*p=..., can repoint.int* const p
*p=....const int* const p
Step 6 — An object is a box of boxes; this is the hidden pointer
WHAT. A class object bundles several data boxes together. Every member function secretly receives a pointer to the object it was called on, named this. Inside Circle::area(), this is how the code reaches r.
WHY. We already know how to paint a pointer's target red (Step 3). A const member function does exactly that to this. So member-function const-ness is not a new concept — it is Step 3 applied to the hidden this pointer.
PICTURE. s06 draws a Circle object as an outer box containing one inner box r. A yellow arrow labelled this comes in from the method. In a normal method the arrow's target is green.

Step 7 — const after a method paints this's target red
WHAT. Put const after the parameter list of a member function. This upgrades the hidden pointer from Circle* to const Circle*. By Step 3, every data box inside becomes read-only for that function.
WHY. Two payoffs. (1) The compiler now catches any accidental write to a member — a free bug detector. (2) It's the only way a const object can be used at all: a const Circle c; hands its methods a const Circle* this, so only methods willing to accept that (the const ones) will compile.
PICTURE. s07 mirrors s06 but the this arrow's target is now red — reading r is fine, r = ... is rejected.

This is also why containers give you two operator[] — a const one returning a read-only reference, a non-const one returning a writable reference. See const operator[].
Step 8 — The degenerate cases: mutable, and the shallowness of const
WHAT. Two boundary cases the neat picture must still cover.
mutable. A member markedmutableis painted green even when the object is const. It's a deliberate hole in the red wall — for caches, counters, mutexes: state that doesn't change what the object means.- Shallow const. Painting an object red paints its own boxes red — including a pointer member's box. But the box that pointer points at is a different object and stays green.
constis bitwise/shallow, not deep.
WHY. Ignore these and you'll hit two surprises: "why did cacheHits++ compile inside a const method?" (it's mutable) and "why can I still edit *ptr through a const object?" (const stopped at the pointer box, Step 3-style).
PICTURE. s08 shows a red const object. One inner member is a mutable counter drawn green (a gap in the red wall). Another member is a pointer: its own box is red (can't repoint) but the far box it targets is green (still writable) — the shallow edge.

The one-picture summary
Every rule on this page is the same question asked about a different box: "through this name, is writing green or red?"

- Variable:
constpaints the one box red. - Pointer: there are two boxes;
conston the left of*reddens the target, on the right of*reddens the pointer. - Object: the hidden
thispointer;constafter the method reddens its target, so all members read-only — withmutablea green gap and pointer-targets staying green (shallow).
Recall Feynman retelling — the whole walkthrough in plain words
Think of memory as boxes you can look into and put things into. Writing const in front of a name paints that box red: you may still read it, but you may not write it — and because a red box can never be written, you must fill it the moment you make it.
A pointer is a second box: instead of a value it holds an address, an arrow to another box. Now there are two boxes, so const has two possible things to paint. The trick is where you write const. Left of the star, it paints the box the arrow lands on — you can look but not touch the data, yet you can swing the arrow anywhere. Right of the star, it paints the pointer box itself — the arrow is glued in place, but you can freely edit the box it lands on. Write const on both sides and both boxes are red.
An object is a box holding smaller boxes, and every method secretly gets an arrow called this reaching into it. A const after the method is just "left-of-the-star const" applied to that hidden arrow: it reddens all the member boxes, so the method can read but not write. That's why a red (const) object can only call red (const) methods — those are the only ones that accept a red arrow. The escape hatches: a mutable member stays green even in a red object, and if a member is itself a pointer, only its box goes red while the faraway box it points to stays green — because the red paint is shallow, one box deep.
Recall Quick self-test
Where does const in const int* p apply, left or right? ::: To the thing on its left — but nothing is there, so it falls to the right: the int. The pointee is red.
Why must int* const p be initialized? ::: p is a red box (const pointer); a red box can only be written at birth.
What type is this inside a const method of Widget? ::: const Widget*.
A const object holds an int* q. Can you do *q = 5? ::: Yes — const is shallow; q's box is red (can't repoint) but its target stays green.