C++ Access Specifiers

Controlling access to class members

🔒 What are Access Specifiers?

Access specifiers control the visibility and accessibility of class members. They determine which parts of your code can access specific data and methods within a class.


class MyClass {
private:
    int secretData;      // Only accessible within class
    
public:
    int publicData;      // Accessible from anywhere
    
    void setSecret(int value) {
        secretData = value;  // OK: inside class
    }
};
                                    

Access Control:

private: Internal use only
public: External access allowed

Types of Access Specifiers

🔓

Public

Accessible from anywhere in the program

public:
    int data;
    void method();
🔒

Private

Only accessible within the same class

private:
    int secretData;
    void helper();
🔐

Protected

Accessible in class and derived classes

protected:
    int inheritedData;
    void baseMethod();
🛡️

Encapsulation

Hide internal implementation details

private:
    void validateInput();
public:
    void setData(int val);

🔹 Public Access Specifier

Public members of a class are accessible from any part of the program, including outside the class. This includes methods and properties that form the class's interface. While public access facilitates interaction with objects, it should be used judiciously to maintain encapsulation. Overexposing internal state can lead to fragile code that is difficult to refactor and secure.

#include <iostream>
#include <string>
using namespace std;

class Car {
public:
    // Public data members
    string brand;
    string model;
    int year;
    
    // Public methods
    void startEngine() {
        cout << "Engine started!" << endl;
    }
    
    void displayInfo() {
        cout << brand << " " << model << " (" << year << ")" << endl;
    }
    
    void honk() {
        cout << "Beep beep!" << endl;
    }
};

int main() {
    Car myCar;
    
    // Accessing public members directly
    myCar.brand = "Toyota";
    myCar.model = "Camry";
    myCar.year = 2023;
    
    // Calling public methods
    myCar.displayInfo();
    myCar.startEngine();
    myCar.honk();
    
    return 0;
}

Output:

Toyota Camry (2023)
Engine started!
Beep beep!

🔹 Private Access Specifier

Private members are only accessible within the class where they are declared, hiding implementation details. This strict encapsulation prevents external code from directly modifying internal state, reducing bugs and unintended side effects. Access to private data is typically provided through public getter and setter methods, allowing controlled interaction and validation.

class BankAccount {
private:
    // Private data members
    double balance;
    string accountNumber;
    string pin;
    
    // Private helper method
    bool validatePin(string inputPin) {
        return pin == inputPin;
    }
    
public:
    // Constructor
    BankAccount(string accNum, string userPin, double initialBalance) {
        accountNumber = accNum;
        pin = userPin;
        balance = initialBalance;
        cout << "Account created: " << accountNumber << endl;
    }
    
    // Public methods to access private data
    double getBalance(string inputPin) {
        if (validatePin(inputPin)) {
            return balance;
        } else {
            cout << "Invalid PIN!" << endl;
            return -1;
        }
    }
    
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            cout << "Deposited: $" << amount << endl;
        }
    }
    
    bool withdraw(double amount, string inputPin) {
        if (validatePin(inputPin) && amount > 0 && amount <= balance) {
            balance -= amount;
            cout << "Withdrawn: $" << amount << endl;
            return true;
        } else {
            cout << "Transaction failed!" << endl;
            return false;
        }
    }
};

int main() {
    BankAccount account("12345", "1234", 1000.0);
    
    // These work - accessing through public methods
    account.deposit(500.0);
    cout << "Balance: $" << account.getBalance("1234") << endl;
    account.withdraw(200.0, "1234");
    
    // This would cause compilation error:
    // cout << account.balance;  // ERROR: balance is private
    
    return 0;
}

Output:

Account created: 12345
Deposited: $500
Balance: $1500
Withdrawn: $200

🔹 Protected Access Specifier

Protected members are accessible within the class and its derived classes, but not from unrelated code. This specifier strikes a balance between encapsulation and inheritance, allowing subclasses to reuse and extend base class functionality while still hiding details from the outside world. It is essential for building extensible class hierarchies in object-oriented design.

class Animal {
protected:
    // Protected members - accessible in derived classes
    string species;
    int age;
    
    void sleep() {
        cout << "Animal is sleeping..." << endl;
    }
    
public:
    Animal(string s, int a) {
        species = s;
        age = a;
    }
    
    void displayBasicInfo() {
        cout << "Species: " << species << ", Age: " << age << endl;
    }
};

class Dog : public Animal {
private:
    string breed;
    
public:
    Dog(string s, int a, string b) : Animal(s, a) {
        breed = b;
    }
    
    void displayFullInfo() {
        // Can access protected members from base class
        cout << "Species: " << species << endl;  // OK: protected
        cout << "Age: " << age << endl;          // OK: protected
        cout << "Breed: " << breed << endl;
    }
    
    void takeNap() {
        cout << "Dog is taking a nap..." << endl;
        sleep();  // OK: can call protected method
    }
};

int main() {
    Dog myDog("Canine", 3, "Golden Retriever");
    
    myDog.displayBasicInfo();  // Public method
    myDog.displayFullInfo();   // Public method accessing protected data
    myDog.takeNap();
    
    // This would cause error:
    // cout << myDog.species;  // ERROR: protected member not accessible here
    
    return 0;
}

Output:

Species: Canine, Age: 3
Species: Canine
Age: 3
Breed: Golden Retriever
Dog is taking a nap...
Animal is sleeping...

🔹 Complete Example with All Specifiers

A comprehensive class example demonstrates the strategic use of public, private, and protected access specifiers. Public methods define the API, private members secure internal data, and protected members facilitate inheritance. For instance, a Manager class might publicly expose calculateBonus(), keep salary private, and share department info with subclasses via protected access, ensuring clean architecture.

class Employee {
private:
    // Private - only accessible within Employee class
    double salary;
    string socialSecurityNumber;
    
protected:
    // Protected - accessible in Employee and derived classes
    string department;
    int employeeId;
    
    void calculateBonus() {
        cout << "Calculating bonus..." << endl;
    }
    
public:
    // Public - accessible from anywhere
    string name;
    string position;
    
    Employee(string n, string pos, string dept, int id, double sal) {
        name = n;
        position = pos;
        department = dept;
        employeeId = id;
        salary = sal;
    }
    
    // Public getter methods for private data
    double getSalary() {
        return salary;
    }
    
    void setSalary(double newSalary) {
        if (newSalary > 0) {
            salary = newSalary;
        }
    }
    
    void displayPublicInfo() {
        cout << "Name: " << name << endl;
        cout << "Position: " << position << endl;
    }
};

class Manager : public Employee {
private:
    int teamSize;
    
public:
    Manager(string n, string pos, string dept, int id, double sal, int team) 
        : Employee(n, pos, dept, id, sal) {
        teamSize = team;
    }
    
    void displayManagerInfo() {
        cout << "Manager: " << name << endl;           // Public: OK
        cout << "Department: " << department << endl;  // Protected: OK
        cout << "Employee ID: " << employeeId << endl; // Protected: OK
        cout << "Team Size: " << teamSize << endl;
        // cout << salary;  // ERROR: private member not accessible
    }
    
    void giveBonus() {
        calculateBonus();  // Protected method: OK
    }
};

int main() {
    Manager mgr("Alice Johnson", "Senior Manager", "IT", 1001, 75000, 8);
    
    // Public access
    cout << "Manager Name: " << mgr.name << endl;
    mgr.displayPublicInfo();
    mgr.displayManagerInfo();
    mgr.giveBonus();
    
    // Private access through public method
    cout << "Salary: $" << mgr.getSalary() << endl;
    
    return 0;
}

Output:

Manager Name: Alice Johnson
Name: Alice Johnson
Position: Senior Manager
Manager: Alice Johnson
Department: IT
Employee ID: 1001
Team Size: 8
Calculating bonus...
Salary: $75000

🧠 Test Your Knowledge

Which access specifier allows access only within the same class?