CppEncapsulation

Encapsulation

Encapsulation is the practice of bundling an object's data together with the functions that operate on it, and restricting direct access to that data from outside the class. Instead of letting any code anywhere reach in and change a member variable directly, you expose a controlled interface — typically a set of public methods — through which the outside world is allowed to interact with the object.

Restricting access

In C++, encapsulation is enforced with access specifierspublic, private, and protected — covered in full on the next page. For now, the key idea is simple: mark member variables private, and provide public methods for the operations you actually want to allow.

Hiding internal state behind a public interface

CPP
class BankAccount {
private:
    double balance; // hidden — no outside code can touch this directly

public:
    BankAccount(double initialBalance) : balance(initialBalance) {}

    void deposit(double amount) {
        if (amount > 0) balance += amount; // invariant enforced here
    }

    bool withdraw(double amount) {
        if (amount <= 0 || amount > balance) return false; // reject invalid withdrawals
        balance -= amount;
        return true;
    }

    double getBalance() const {
        return balance;
    }
};
Why this matters
  • Protecting invariantsBankAccount guarantees balance never goes negative because every path that changes it goes through code that checks first. If balance were public, any code anywhere could set it to an invalid value.

  • Freedom to change the implementation — the internal representation of BankAccount (a double, cents as an int, a ledger of transactions) can change later without breaking any code that calls deposit(), withdraw(), and getBalance(). The public interface is a stable contract; the internals are free to evolve.

  • A single place to reason about correctness — if something goes wrong with balance, you only need to look inside BankAccount's own methods, not search the entire codebase for anywhere it might have been modified.

Getters and setters

The classic encapsulation pattern pairs a private member with public accessor (getter) and mutator (setter) methods, as getBalance() does above. Setters are the natural place to put validation logic — as deposit() and withdraw() do by rejecting invalid amounts.

Don't over-encapsulate trivially
Writing a private member with a getter and a setter that do nothing but return or assign the value — with no validation, no invariant, no computed behavior — doesn't actually add any protection. It just adds boilerplate while giving the illusion of encapsulation. Ask what the getter/setter is protecting; if the answer is “nothing,” a plain public member (or a `struct`) is often the more honest design.
What's next
  • The mechanics behind public/private/protected, and how they interact with inheritance, are covered next in Access Specifiers.