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