Encapsulation
Encapsulation and Access Specifiers
Section titled “Encapsulation and Access Specifiers”Encapsulation is the bundling of data and methods that operate on that data within a single unit (class). It also restricts direct access to some of an object’s components, which is a means of preventing unintended interference.
What is Encapsulation?
Section titled “What is Encapsulation?”┌─────────────────────────────────────────────────────────────┐│ Encapsulation Concept │├─────────────────────────────────────────────────────────────┤│ ││ Without Encapsulation With Encapsulation ││ ┌─────────────┐ ┌─────────────┐ ││ │ Account │ │ Account │ ││ ├─────────────┤ ├─────────────┤ ││ │ balance: 100│ │ - balance │ ← private ││ ├─────────────┤ │ + getBalance│ ← public ││ │ withdraw() │ │ + deposit() │ ││ │ deposit() │ │ + withdraw()│ ││ └─────────────┘ └─────────────┘ ││ ││ Anyone can modify Controlled access through ││ balance directly public methods ││ │└─────────────────────────────────────────────────────────────┘Access Specifiers in Detail
Section titled “Access Specifiers in Detail”Private Members
Section titled “Private Members”Only accessible within the same class:
class BankAccount {private: double balance; // Only BankAccount can access
public: void deposit(double amount) { if (amount > 0) { balance += amount; // OK - same class } }};
int main() { BankAccount account; // account.balance = 1000000; // Error! Private account.deposit(100); // OK - through public method}Protected Members
Section titled “Protected Members”Accessible in the class and derived classes:
class Animal {protected: std::string name; // Accessible in Animal and subclasses
public: Animal(const std::string& n) : name(n) {}};
class Dog : public Animal {public: Dog(const std::string& n) : Animal(n) {}
void displayName() { std::cout << name << std::endl; // OK - derived class }};Public Members
Section titled “Public Members”Accessible everywhere:
class Rectangle {public: double width; double height;};
int main() { Rectangle r; r.width = 5; // OK - public r.height = 3; // OK - public}Getters and Setters
Section titled “Getters and Setters”Control access to private data:
class Person {private: std::string name; int age;
public: // Getters std::string getName() const { return name; } int getAge() const { return age; }
// Setters with validation void setName(const std::string& n) { if (!n.empty()) { name = n; } }
void setAge(int a) { if (a >= 0 && a <= 150) { age = a; } }};Why Encapsulation?
Section titled “Why Encapsulation?”1. Data Protection
Section titled “1. Data Protection”// Without encapsulation - unsafeclass Account {public: double balance;};
Account acc;acc.balance = -1000000; // Invalid! No validation
// With encapsulation - safeclass Account {private: double balance = 0;
public: void deposit(double amount) { if (amount > 0) { // Validation balance += amount; } }};2. Implementation Flexibility
Section titled “2. Implementation Flexibility”class List {private: // Could be array, linked list, vector, etc. // Change implementation without breaking user code std::vector<int> data;
public: void add(int value) { data.push_back(value); // Implementation detail }};3. Code Maintainability
Section titled “3. Code Maintainability”class Temperature {private: double celsius;
public: double getCelsius() const { return celsius; }
// If we change to store Fahrenheit internally, // only this method needs to change double getFahrenheit() const { return celsius * 9/5 + 32; }};The Uniform Initialization Principle (C++11)
Section titled “The Uniform Initialization Principle (C++11)”class Point {private: double x, y;
public: // Constructors Point() : x(0), y(0) {} Point(double xVal, double yVal) : x(xVal), y(yVal) {}
// Getter with const correctness double getX() const { return x; } double getY() const { return y; }};Const Member Functions
Section titled “Const Member Functions”Mark methods that don’t modify object state:
class Circle {private: double radius;
public: Circle(double r) : radius(r) {}
// Won't modify any member variables double getRadius() const { return radius; }
// Will modify member - can't be const void setRadius(double r) { radius = r; }
double area() const { // radius = 10; // Error! Can't modify in const function return 3.14159 * radius * radius; }};Complete Example: Bank Account with Encapsulation
Section titled “Complete Example: Bank Account with Encapsulation”#include <iostream>#include <string>#include <vector>#include <stdexcept>
class InsufficientFundsException : public std::exception {public: const char* what() const noexcept override { return "Insufficient funds for this operation"; }};
class InvalidAmountException : public std::exception {public: const char* what() const noexcept override { return "Invalid amount provided"; }};
class BankAccount {private: // Private data - hidden from outside std::string accountNumber; std::string ownerName; double balance; std::vector<std::string> transactionHistory;
// Private helper methods void addToHistory(const std::string& transaction) { transactionHistory.push_back(transaction); }
public: // Constructor BankAccount(const std::string& accNum, const std::string& owner) : accountNumber(accNum), ownerName(owner), balance(0) {}
// Public interface - controlled access
// Getters (read-only) std::string getAccountNumber() const { return accountNumber; } std::string getOwnerName() const { return ownerName; } double getBalance() const { return balance; }
// Transaction methods with validation void deposit(double amount) { if (amount <= 0) { throw InvalidAmountException(); } balance += amount; addToHistory("Deposit: $" + std::to_string(amount)); }
void withdraw(double amount) { if (amount <= 0) { throw InvalidAmountException(); } if (amount > balance) { throw InsufficientFundsException(); } balance -= amount; addToHistory("Withdrawal: $" + std::to_string(amount)); }
// Read-only access to history const std::vector<std::string>& getHistory() const { return transactionHistory; }
// Display account info void display() const { std::cout << "Account: " << accountNumber << "\n"; std::cout << "Owner: " << ownerName << "\n"; std::cout << "Balance: $" << balance << "\n"; }};
int main() { try { BankAccount account("123456", "John Doe");
// Deposit money (through controlled interface) account.deposit(1000); account.deposit(500);
// Try invalid deposit // account.deposit(-100); // Throws exception
// Withdraw account.withdraw(200);
// Try to withdraw too much // account.withdraw(10000); // Throws exception
account.display();
std::cout << "\nTransaction History:\n"; for (const auto& txn : account.getHistory()) { std::cout << txn << "\n"; }
} catch (const std::exception& e) { std::cout << "Error: " << e.what() << "\n"; }
return 0;}Access Specifiers Best Practices
Section titled “Access Specifiers Best Practices”| Guideline | Example |
|---|---|
| Keep data private | private: double balance; |
| Provide public getters/setters when needed | public: double getBalance() const; |
Use const for read-only access | double getValue() const; |
| Validate input in setters | void setAge(int a) { if (a >= 0) age = a; } |
| Minimize public members | Only expose what’s necessary |
Key Takeaways
Section titled “Key Takeaways”- Encapsulation bundles data and methods, restricting direct access
private- only accessible within the classprotected- accessible in class and derived classespublic- accessible everywhere- Use getters and setters for controlled access
- Always use
constfor methods that don’t modify state - Encapsulation provides data protection, implementation flexibility, and maintainability
Next Steps
Section titled “Next Steps”Now let’s learn about friend functions and operator overloading.
Next Chapter: 13_friend_functions.md - Friend Functions and Operator Overloading