SyntaxStudy
Sign Up
C++ Encapsulation and Access Specifiers
C++ Beginner 1 min read

Encapsulation and Access Specifiers

Object-oriented programming in C++ is built on three pillars: encapsulation, inheritance, and polymorphism. Encapsulation bundles data and the functions that operate on it into a single class, hiding internal representation from external code. This principle is enforced through access specifiers: 'public' members are accessible everywhere, 'protected' members are accessible within the class and its subclasses, and 'private' members are accessible only within the class itself. By default, members of a 'class' are 'private', while members of a 'struct' are 'public'. Choosing the right access level for each member is a design decision: data members should generally be 'private', exposed only through 'public' accessor and mutator methods that can validate inputs and maintain class invariants. Friend declarations allow specific external functions or classes to bypass access restrictions. While friends can be useful for tightly coupled components — such as operator overloads — they should be used sparingly, as they weaken encapsulation and increase coupling between otherwise independent entities.
Example
#include <iostream>
#include <string>
#include <stdexcept>

class BankAccount {
public:
    // Constructor — public interface for creation
    explicit BankAccount(const std::string& owner, double initial = 0.0)
        : owner_(owner), balance_(initial) {
        if (initial < 0) throw std::invalid_argument("Negative balance");
    }

    // Public accessors (getters)
    std::string owner()  const { return owner_;  }
    double      balance() const { return balance_; }

    // Public mutators with validation
    void deposit(double amount) {
        if (amount <= 0) throw std::invalid_argument("Amount must be positive");
        balance_ += amount;
    }

    void withdraw(double amount) {
        if (amount <= 0) throw std::invalid_argument("Amount must be positive");
        if (amount > balance_) throw std::runtime_error("Insufficient funds");
        balance_ -= amount;
    }

private:
    std::string owner_;   // private data
    double      balance_; // private data

    // Private helper — not part of public API
    void log(const std::string& msg) const {
        std::cout << "[" << owner_ << "] " << msg << "\n";
    }
};

int main() {
    BankAccount acc("Alice", 1000.0);
    acc.deposit(250.0);
    acc.withdraw(100.0);
    std::cout << acc.owner() << " balance: " << acc.balance() << "\n";
    return 0;
}