Afzal Badshah, PhD

Encapsulation in C++: A Beginner Guide

Encapsulation in object-oriented programming is a core principle. It helps keep data safe and programs modular. Imagine a School Management App: students can view their class (through a getter), but only the administration system can update it (using a setter). This story highlights how encapsulation mirrors real-world roles. Encapsulation ensures data safety and modular design.

Imagine using a car or a smartphone: you interact with simple controls on the surface, while the complicated wiring and mechanisms are hidden inside. This is exactly what encapsulation provides in software engineering.

“Encapsulation is the practice of hiding the internal details and exposing only what is necessary through a well-defined interface.”

This principle simplifies usage by concealing complexity, allows internal changes without breaking external code, and protects data integrity.

Access Specifiers

Access specifiers in C++ determine the visibility and accessibility of members inside and outside of a class. They help enforce encapsulation by controlling how data and functions can be used.

Public

Public members are the part of a class interface that can be freely accessed from outside. They usually represent operations the object exposes.

Public Access Specifiers

Syntax:

class Example {
public:
    int x; // accessible everywhere
};

Accessible from outside the class.

Private

Private members hold a class’s internal details and are not visible outside the class. Use private to enforce invariants and prevent arbitrary external mutation; only member functions (and declared friends) can access them.

Private Access Specifiers

Syntax:

class Example {
private:
    int y; // accessible only within the class
};

Restricted to the class itself.

Protected

Protected members are intended for collaboration with derived classes. They enable extension in subclasses while staying hidden from non-member, non-friend code—use sparingly to avoid tight coupling to internals.

Protected Access Specifiers

Syntax:

class Example {
protected:
    int z; // accessible in class and derived classes
};

Accessible within the class and derived classes.

Access SpecifierSame ClassDerived ClassOutside World
public
protected
private

Demonstrating Access Specifiers with a Student Class

To better understand the behavior of public, private, and protected, let’s create a Student class. This class will have data members such as name, className, and address, and we will experiment with placing them under different access specifiers.

class Student {
public:
    string name;      // Public: accessible directly from outside

private:
    string className; // Private: hidden from outside, only accessible inside class

protected:
    string address;   // Protected: accessible in this class and in derived classes
};

By changing the access specifier, you can observe which members are accessible from outside, which are hidden, and which are reserved for inheritance.

Complete Program Demonstrating Access Specifiers

#include <iostream>
using namespace std;

class Student {
public:
    string name;   // public

private:
    string className; // private

protected:
    string address;   // protected

public:
    void showInfo() {
        cout << "Name: " << name << endl;
        cout << "Class: " << className << endl;
        cout << "Address: " << address << endl;
    }
};

int main() {
    Student s;
    s.name = "Ali";        // allowed (public)
    // s.className = "BSSE"; // error (private)
    // s.address = "City";   // error (protected)

    s.showInfo();

    return 0;
}

Output (conceptual)

Name: Ali
Class: 
Address: 

This simple program demonstrates how public members are accessible, while private and protected members are restricted.

Getters and Setters for Private Members

When class data members are marked as private, they cannot be accessed directly from outside the class. To read or write their values safely, we use special functions called getter and setter.

Example with Student Class

#include <iostream>
using namespace std;

class Student {
private:
    string className; // private member

public:
    void setClassName(string c) {
        className = c;   // setter assigns value
    }

    string getClassName() {
        return className; // getter returns value
    }
};

int main() {
    Student s;
    s.setClassName("BSSE");      // using setter to set value
    cout << s.getClassName();    // using getter to get value
    return 0;
}

Explanation

This ensures data hiding and controlled access to private fields.

Protected Members with Derived Class

When a data member is declared as protected, it is not accessible from outside the class, but it can be accessed inside the class itself and inside its derived classes. This makes protected useful when you want child classes to reuse or extend internal details without exposing them to everyone.

Example with Student and GraduateStudent

#include <iostream>
using namespace std;

class Student {
protected:
    string address; // protected member

public:
    void setAddress(string a) {
        address = a;
    }
};

class GraduateStudent : public Student {
public:
    void showAddress() {
        cout << "Address: " << address << endl;
    }
};

int main() {
    GraduateStudent gs;
    gs.setAddress("University Campus"); // setter from base class
    gs.showAddress(); // derived class accesses protected member
    return 0;
}

Explanation

Exit mobile version