Intermediate 11 min

Access Modifiers

Control access to class members with public, private, and protected modifiers to enforce encapsulation

Master the three access modifiers in C++ to control who can access class members and protect your data from invalid modifications.

A Simple Example

#include <iostream>
#include <string>

class Player {
private:
    int health;
    int maxHealth;
    std::string secretCode;

protected:
    int experiencePoints;

public:
    std::string name;

    Player(std::string playerName, int hp)
        : name{playerName}, health{hp}, maxHealth{hp}, experiencePoints{0}, secretCode{"XYZ123"} {
    }

    void heal(int amount) {
        if (amount > 0) {
            health += amount;
            if (health > maxHealth) health = maxHealth;
            std::cout << "Healed " << amount << " HP\n";
        } else {
            std::cout << "Invalid heal amount" << "\n";
        }
    }

    bool takeDamage(int amount) {
        if (amount <= 0) {
            std::cout << "Invalid damage amount" << "\n";
            return false;
        }
        health -= amount;
        if (health < 0) health = 0;
        std::cout << "Took " << amount << " damage\n";
        return health > 0;
    }

    int getHealth() const {
        return health;
    }
};

int main() {
    Player player{"Alice", 100};

    player.name = "Alice the Brave";  // OK - public
    player.heal(20);                   // OK - public method

    std::cout << "Current health: " << player.getHealth() << "\n";

    // player.health = 999999;    // ERROR - health is private!
    // player.secretCode = "0";   // ERROR - secretCode is private!

    return 0;
}

Breaking It Down

private - Internal Implementation

  • What it does: Only accessible within the class itself - completely hidden from outside
  • Default for classes: If you don't specify, members are private by default
  • Use for: Internal data and helper methods that should never be accessed directly
  • Remember: Private means "no one else's business" - protects invariants and prevents misuse

public - External Interface

  • What it does: Accessible from anywhere - inside or outside the class
  • Use for: Methods that form the public API, constructors, and occasionally data
  • Guideline: Keep data private, make methods public
  • Remember: Public members are your contract with users - changing them breaks code

protected - Inheritance Access

  • What it does: Accessible within the class and its derived classes
  • Use for: Data and methods that subclasses need but external code shouldn't access
  • Common scenario: Shared state or utility functions for a class hierarchy
  • Remember: Protected is for inheritance - if you're not using inheritance, stick to private and public

Encapsulation - The Golden Rule

  • What it is: Hide internal details, expose only necessary functionality
  • Pattern: Keep data private, provide public getter/setter methods
  • Benefit: Change internal implementation without breaking external code
  • Remember: Getters should be const methods since they don't modify the object

Why This Matters

  • Imagine building a car where anyone can reach in and change the engine temperature or fuel level directly. That's what happens without access modifiers - chaos and bugs.
  • Access modifiers are the locks and keys of object-oriented programming. They protect your data from invalid modifications and let you change internal implementation without breaking code that uses your class.
  • This is fundamental to writing professional, maintainable software. Master access modifiers and you control the boundaries of your objects.

Critical Insight

Keep data private, provide public methods. This is encapsulation's golden rule. Why? Because you can change the internal representation without breaking code that uses your class. Want to change how health is stored internally? Easy - just update the implementation. External code never notices!

// Version 1: Health as absolute value
class Player {
private:
    int health;
    int maxHealth;
public:
    int getHealth() const { return health; }
    double getHealthPercent() const { return 100.0 * health / maxHealth; }
};

// Version 2: Health as percentage (changed implementation!)
class Player {
private:
    double healthPercent;  // now stored as 0.0 to 1.0
public:
    int getHealth() const { return static_cast<int>(healthPercent * 100); }
    double getHealthPercent() const { return healthPercent * 100; }
};
// External code doesn't need to change!

Best Practices

Make data members private by default: Protect your internal state and provide controlled access through public methods.

Use getters and setters for validation: Never expose data directly - provide methods that can validate input and maintain invariants.

Mark getters as const: Since getters don't modify the object, declare them with const to prevent accidental changes.

Keep the public interface minimal: Every public member is a commitment. Make only what's necessary public to reduce coupling.

Common Mistakes

Making everything public: New programmers often make all members public for convenience, defeating the purpose of encapsulation.

Direct access to private members: Trying to access private members from outside the class causes compilation errors. Use public methods instead.

Forgetting const on getters: Getters should be const methods since they don't modify the object. Without const, they can't be called on const objects.

struct vs class default: Structs default to public, classes default to private. Be explicit about access modifiers to avoid confusion.

Debug Challenge

This class exposes the health publicly. Click the highlighted line to fix the access modifier:

1 #include <iostream>
2
3 class Player {
4 public:
5 int health;
6 void heal(int amount) {
7 health += amount;
8 }
9 };

Quick Quiz

  1. What is the default access level for class members?
private
public
protected
  1. Which access modifier should you use for data that needs validation before being changed?
private with public setter methods
public - anyone should access it
protected - it's in the middle
  1. Can a private method call a public method in the same class?
Yes, all members can access each other within the same class
No, private can't access public
Only if marked as friend

Practice Playground

Time to try out what you just learned! Play with the example code below, experiment by making changes and running the code to deepen your understanding.

Lesson Progress

  • Fix This Code
  • Quick Quiz
  • Practice Playground - run once