Lesson content
Read, practise, then check your understanding
Encapsulation groups data with operations that preserve its rules. private members are accessible to the class and friends, protected also exposes them to derived classes, and public forms the client interface. Data hiding is a mechanism; a stable abstraction is the goal.
#include <stdexcept>
class Percentage {
double value_{};
public:
explicit Percentage(double value) { set(value); }
double value() const noexcept { return value_; }
void set(double value) {
if (value < 0.0 || value > 100.0) {
throw std::out_of_range{"percentage"};
}
value_ = value;
}
};
Making value_ public would allow invalid state. A setter is valuable only when mutation is meaningful and validated; do not generate getters and setters mechanically for every field.
Boundaries and coupling
Keep implementation details out of public headers when build isolation or binary stability matters. A private implementation (pImpl) can hide heavy dependencies behind an owning pointer. Prefer composition over inheritance when one object simply has another capability.
Const member functions expose read-only behavior. Return values or views whose lifetime is clear; returning mutable references to internals can bypass invariants. Classes should have focused responsibilities, minimal public APIs, and dependencies passed explicitly. Strong encapsulation makes internal representation replaceable without rewriting clients and localizes the proof that every valid object stays valid.
Knowledge check
Answer every question correctly to complete this chapter.
0 of 10 checks passed
Your progress is saved on this device.