Module 4 — Encapsulation¶
After this module you can design a class whose callers cannot put it into an invalid state, and justify every member of its public interface.
At a glance¶
| Prerequisites | Module 3 |
| Estimated study time | 7–9 hours |
| Lab | Lab 4 — sealed types with enforced invariants |
| Exercises | Three tiers — warm-up, core, challenge |
| Cognitive levels | L2 Apply → L5 Design — exit level L5 Design |
| Self-assessment | Module quiz |
Why this module matters¶
Making data private is easy. Knowing why you did it is the difference between
encapsulation and superstition — and the difference shows up the moment
requirements change.
Consider a class that stores a member's borrowed-item count as a plain int
member. Nothing stops another part of the program from setting it to -1. One
month later, a second place sets it, then a third. The rule "the count is never
negative" exists only in the programmer's head, and it is enforced nowhere.
Encapsulation is the practice of turning rules like that into something the compiler and the class itself enforce. You will learn to work in this order — invariant first, then interface, then representation — rather than the usual reverse of writing public fields and hoping.
A useful test you will apply repeatedly: if I changed the private representation completely, would any correct caller need to change? If yes, the interface leaked its implementation.
Learning objectives¶
By the end of this module you will be able to:
- [L2 Apply] Define the invariant of a class, and write it down in one sentence.
- [L5 Design] Design a class in the order: invariant → public interface → private representation.
- [L2 Apply] Keep data members
privateand expose behaviour rather than raw state. - [L2 Apply] Write
constmember functions, and explain why a class that is notconst-correct cannot be used withconstobjects. - [L4 Analyze] Explain what
mutabledoes, and apply the test that decides whether its use is justified. - [L4 Analyze] Use
friendfunctions or classes deliberately, and state the coupling cost of doing so. - [L4 Analyze] Distinguish a getter that exposes state from a method that expresses a capability, and defend each choice with the caller's need rather than a preference.
- [L5 Design] Judge when a setter should not exist at all, and design the operation that replaces it.
- [L4 Analyze] Explain cohesion and coupling, and use them to explain why one class design is better than another.
- [L5 Design] Change a private representation without breaking any correct caller, and demonstrate that this is true.
This module's exit level is 5 Design: you are finished when you can produce an interface for a type, justify every public member by a caller's need, and show that a caller cannot put the object into a state its invariant forbids.
Core concepts¶
- Encapsulation — bundling data with the operations on it, and controlling access to the data.
- Abstraction — presenting what something does while hiding how it does it. Encapsulation is the mechanism; abstraction is the benefit.
- Information hiding — a caller cannot depend on what it cannot see.
- Invariant — the property that must hold for every valid object, at every moment its public interface is not executing. Established in constructors; preserved by every public operation.
- Interface vs implementation — what callers may depend on, versus what may change freely.
constmember function — declares that calling it does not modify the object's observable state, so it can be called onconstobjects.const-correctness — marking everything that can beconstasconst, which turns "you modified something you should not have" into a compile error.- Overloading on
const— providing both aconstand a non-constversion of the same member function, commonly foroperator[]. mutable— allows a member to be modified inside aconstmember function. Legitimate for caches and locks; a red flag anywhere else.friend— grants one specific function or class access to private members. Sometimes necessary (typically foroperator<<), always a coupling decision.- Accessor vs capability —
getBalance()exposes state;canAfford(price)expresses a question the class can answer. The second keeps the rule inside the class. - Cohesion — how single-mindedly a class does one job.
- Coupling — how much one part of a program must know about another. The aim is high cohesion and low coupling.
Module contents¶
| Section | What it contains |
|---|---|
| Introduction (this page) | Overview, prerequisites, objectives, concept inventory |
| Concepts and explanations | Why private is not encapsulation, invariant-first design, capabilities versus accessors, the four leaks, const-correctness, mutable, friend, cohesion and coupling |
| Worked examples | Four programs — including one interface with two representations — plus a worked interface design |
| Code examples | examples/module-04/ — four programs; the representation swap builds twice and must diff silently |
| Misconceptions and mistakes | Eight wrong mental models, three real messages, and the two silences |
| Debugging | The attack test, the three silent failures, and the escalation ladder |
| Exercises | Three tiers, including an attack analysis and a representation swap |
| Lab 4 | Seal the running system, and justify every public member in writing |
| Challenge problems | A rule spanning two types, a justification review, and a sealed refactor |
| Self-assessment | Nine questions, including four verdicts on four signatures |
| Summary | What must be retained, the terms to be able to define, and the checklist |
| Further reading | Books and official documentation |
What you can do after this module¶
- Write a class and state its invariant in one sentence.
- Refuse a
setaccessor with a reason, not a preference. - Reproduce the example where changing the private representation breaks nothing, which is the proof that encapsulation worked.
- Explain why a
constobject cannot call a non-constmember function, and fix it correctly rather than by casting awayconst.
Where this is used later¶
const-correctness is required for the operator overloads in Module 5 and for using your types in standard containers in Module 14.- Invariants are what inheritance must preserve in Module 6, and what contracts formalise in Module 8.
friendandoperator<<are covered together in Module 5.- Cohesion and coupling are the raw material of the SOLID principles in Module 15.
Common mistakes to watch for¶
| Symptom | Cause |
|---|---|
error: passing 'const Book' as 'this' argument discards qualifiers |
Calling a non-const member function on a const object. Mark the function const if it does not modify the object; do not cast the const away |
A "getter" returns a reference to an internal std::vector |
The caller can now modify internals freely — the invariant is gone. Return a const reference, or offer query methods |
| Every field has a getter and a setter | The class has no interface, only a public representation. Nothing is hidden, so nothing can change safely |
friend added to make something compile |
A design decision disguised as a keyword. Consider whether the operation belongs in the class instead |
| An invariant "sometimes" breaks | It is enforced in more than one place, or in none. Enforce it in exactly one |
Skills checklist¶
Levels this module works at: [L2 Apply → L5 Design] — see How you will learn.
Tick an item only when the evidence exists:
- [ ] I can state a type's invariant in one sentence, above the class — evidence: every type in your Lab 4 solution
- [ ] I can justify every public member by a caller's need — evidence:
justification.md, one row per member, with the deleted members listed too - [ ] I can recognise all four kinds of representation leak — evidence: self-assessment question 3, all four verdicts correct
- [ ] I can swap a private representation without any caller changing — evidence: a silent
diffbetween two builds of your own class - [ ] I can write
const-correct types — evidence: a free function takingconst T&that prints an entire object - [ ] I can judge a
mutableorfriendproposal against its test — evidence: the two sentences justifying each in your own code, or their removal - [ ] I can find a leak by attacking my own class — evidence: your attack file, with the line of each attack and what it does now
- [ ] I can name what a caller can no longer do — evidence: the trade paragraph in challenge X3, naming who is worse off
Suggested next step¶
Previous: Module 3 — Constructors and Destructors · Next: Module 5 — Operators and Static Members · All modules: Modules index