C++ Access Specifiers and Friend Declarations
Class Member Access Control
C++ provides three primary access specifiers for class members: public, private, and protected. By default, class members are private.
| Specifier | Within Class | Derived Class | External Instance |
|---|---|---|---|
| public | Accessible | Accessible | Accessible |
| private | Accessible | Inaccessible | Inaccessible |
| protected | Accessible | Accessible | Inaccessible |
Public Members
Members declared as public have no access restrictions. They can be accessed from within the class, by derived classes, and externally through object instances.
#include <iostream>
class Engine {
public:
Engine(int hp) : horsepower(hp) {
std::cout << "Engine created. HP: " << horsepower << std::endl;
diagnose();
}
~Engine() {
std::cout << "Engine destroyed. HP: " << horsepower << std::endl;
}
void diagnose() {
std::cout << "Running diagnosis. HP: " << horsepower << std::endl;
}
int horsepower;
};
class TurboEngine : public Engine {
public:
TurboEngine() : Engine(500) {
horsepower = 600; // Accessible in derived class
std::cout << "TurboEngine created. HP: " << horsepower << std::endl;
}
};
int main() {
Engine e(100);
e.diagnose(); // Accessible externally
TurboEngine t;
t.diagnose(); // Accessible externally
e.horsepower = 150; // Accessible externally
e.diagnose();
return 0;
}
Private Members
Members declared as private are strictly confined to the class they are declared in. Neither derived classes nor external code can access them.
#include <iostream>
class Vault {
public:
Vault(int code) : secretCode(code) {
std::cout << "Vault created. Code: " << secretCode << std::endl;
validate();
}
~Vault() {
std::cout << "Vault destroyed." << std::endl;
}
private:
void validate() {
std::cout << "Validating code: " << secretCode << std::endl;
}
int secretCode;
};
class SecureVault : public Vault {
public:
SecureVault() : Vault(999) {
// secretCode = 111; // Compile error: private member inaccessible
// validate(); // Compile error: private member inaccessible
}
};
int main() {
Vault v(123);
// v.validate(); // Compile error
// v.secretCode = 0; // Compile error
return 0;
}
Cross-Object Private Access
A member function of a class can access the private members of another instance of the same class.
#include <iostream>
class Player {
public:
Player(int s) : score(s) {}
void compare(const Player& rival) {
// Accessing rival's private score is allowed within the same class
std::cout << "Rival score: " << rival.score << std::endl;
}
private:
int score;
};
int main() {
Player p1(100);
Player p2(200);
p1.compare(p2);
return 0;
}
Protected Members
Members declared as protected act like private members to the outside world, but remain accessible within derived classes.
#include <iostream>
class Sensor {
public:
Sensor(int v) : value(v) {
std::cout << "Sensor initialized. Value: " << value << std::endl;
calibrate();
}
~Sensor() {
std::cout << "Sensor destroyed." << std::endl;
}
protected:
void calibrate() {
std::cout << "Calibrating. Value: " << value << std::endl;
}
int value;
};
class TempSensor : public Sensor {
public:
TempSensor() : Sensor(25) {
value = 30; // Accessible in derived class
calibrate(); // Accessible in derived class
}
};
int main() {
Sensor s(10);
// s.calibrate(); // Compile error: protected member inaccessible externally
// s.value = 5; // Compile error: protected member inaccessible externally
return 0;
}
Inheritance Access Control
When inheriting, the default access specifier is private for classes (and public for structs). The inheritance specifier affects how base class members are perceived by the derived class and its descendants.
| Inheritance Type | Base Public | Base Private | Base Protected |
|---|---|---|---|
| public | Public in derived | Inaccessible | Protected in derived |
| private | Private in derived | Inaccessible | Private in derived |
| protected | Protected in derived | Inaccessible | Protected in derived |
Public Inheritance
Public inheritance preserves the base class access levels. Public members stay public, and protected members stay protected. Private members remain inaccessible.
#include <iostream>
class Animal {
public:
void eat() { std::cout << "Eating" << std::endl; }
int age;
private:
void digest() { std::cout << "Digesting" << std::endl; }
int internalId;
protected:
void sleep() { std::cout << "Sleeping" << std::endl; }
int energy;
};
class Dog : public Animal {
public:
void behavior() {
eat(); // Accessible
// digest(); // Compile error: inaccessible
sleep(); // Accessible
}
};
int main() {
Dog d;
d.eat(); // Accessible externally
// d.digest(); // Compile error
// d.sleep(); // Compile error
return 0;
}
Private Inheritance
Private inheritance makes all public and protected members of the base class private in the derived class. This means external code or further derived classes cannot access them.
#include <iostream>
class Animal {
public:
void eat() { std::cout << "Eating" << std::endl; }
int age;
private:
void digest() { std::cout << "Digesting" << std::endl; }
int internalId;
protected:
void sleep() { std::cout << "Sleeping" << std::endl; }
int energy;
};
class Wolf : private Animal {
public:
void behavior() {
eat(); // Accessible as private member
// digest(); // Compile error: inaccessible
sleep(); // Accessible as private member
}
};
int main() {
Wolf w;
w.behavior();
// w.eat(); // Compile error: eat() is private in Wolf
return 0;
}
Protected Inheritance
Protected inheritance turns public base members into protected members in the derived class, while protected base members remain protected. Private base members are still inaccessible.
#include <iostream>
class Animal {
public:
void eat() { std::cout << "Eating" << std::endl; }
int age;
private:
void digest() { std::cout << "Digesting" << std::endl; }
int internalId;
protected:
void sleep() { std::cout << "Sleeping" << std::endl; }
int energy;
};
class Cat : protected Animal {
public:
void behavior() {
eat(); // Accessible as protected member
// digest(); // Compile error: inaccessible
sleep(); // Accessible as protected member
}
};
int main() {
Cat c;
c.behavior();
// c.eat(); // Compile error: eat() is protected in Cat
return 0;
}
Friend Declarations
The friend keyword allows a class to grant specific external functions or classes full access to its private and protected members. This provides flexibility by bypassing the standard encapsulation rules.
Friend Functions
A friend function can be a standalone function, a member function of another class, or even defined inside the class granting access. The declaration can be placed in any access section (public, private, or protected) without affecting the friendship.
#include <iostream>
class Database;
class Auditor {
public:
void inspect(const Database& db);
};
class Database {
public:
Database() : recordCount(100) {}
void showPublic() { std::cout << "Public interface" << std::endl; }
int recordCount;
friend void scanDatabase(const Database& db);
friend void Auditor::inspect(const Database& db);
friend void quickScan(const Database& db) {
std::cout << "Quick scan accessing secret: " << db.secretKey << std::endl;
}
private:
void showSecret() { std::cout << "Secret interface" << std::endl; }
int secretKey = 42;
protected:
void showInternal() { std::cout <" Internal interface" << std::endl; }
int internalId = 7;
};
void Auditor::inspect(const Database& db) {
std::cout << "Auditor inspecting. Secret: " << db.secretKey << std::endl;
}
void scanDatabase(const Database& db) {
std::cout << "Scanning. Secret: " << db.secretKey << std::endl;
db.showSecret();
db.showInternal();
}
int main() {
Database db;
scanDatabase(db);
Auditor a;
a.inspect(db);
quickScan(db);
return 0;
}
Friend Classes
When an entire class is declared as a friend, all of its member functions gain access to the private and protected members of the granting class.
#include <iostream>
class Network;
class Monitor {
public:
void checkNetwork(const Network& net);
private:
void deepCheck(const Network& net);
protected:
void passiveCheck(const Network& net);
};
class Network {
public:
Network() : port(8080) {}
int port;
friend class Monitor;
private:
int password = 1234;
void secretHandshake() { std::cout << "Handshake" << std::endl; }
protected:
int protocol = 6;
void internalPing() { std::cout << "Ping" << std::endl; }
};
void Monitor::checkNetwork(const Network& net) {
std::cout << "Check network. Pwd: " << net.password << std::endl;
net.secretHandshake();
deepCheck(net);
}
void Monitor::deepCheck(const Network& net) {
std::cout << "Deep check. Protocol: " << net.protocol << std::endl;
net.internalPing();
}
void Monitor::passiveCheck(const Network& net) {
std::cout << "Passive check." << std::endl;
}
int main() {
Network net;
Monitor mon;
mon.checkNetwork(net);
// mon.deepCheck(net); // Compile error: deepCheck is private
return 0;
}