Access Control Exceptions with C++ Friend Declarations
Global Functions as Friends
In C++, the friend keyword allows external functions to bypass the access restrictions of a class. This is useful when a specific standalone function needs to operate on the private data members of an object.
To grannt access, include the function's prototype inside the class definition preceded by the friend keyword.
#include <iostream>
#include <string>
class Residence {
// Granting access to a global function
friend void revealPrivateDetails(const Residence& home);
public:
std::string livingRoom;
Residence() {
this->livingRoom = "Public Living Area";
this->masterBedroom = "Private Master Suite";
}
private:
std::string masterBedroom;
};
void revealPrivateDetails(const Residence& home) {
std::cout << "Visiting: " << home.livingRoom << std::endl;
// Accessing private member permitted by friend declaration
std::cout << "Visiting: " << home.masterBedroom << std::endl;
}
int main() {
Residence myHome;
revealPrivateDetails(myHome);
return 0;
}
Utilizing Friend Classes
You can grant an entire class access to the private members of another class. This establishes a relationship where all member functions of the authorized class can interact with the internals of the target class.
#include <iostream>
#include <string>
class Server;
class AdminPanel {
public:
AdminPanel();
void displayStatus();
private:
Server* connection;
};
class Server {
// Authorizing AdminPanel to access private data
friend class AdminPanel;
public:
std::string ipAddress;
Server() {
this->ipAddress = "192.168.1.1";
this->rootKey = "ADMIN_SECRET_KEY";
}
private:
std::string rootKey;
};
AdminPanel::AdminPanel() {
connection = new Server;
}
void AdminPanel::displayStatus() {
std::cout << "Server IP: " << connection->ipAddress << std::endl;
// Direct access to private member rootKey
std::cout << "Root Access: " << connection->rootKey << std::endl;
}
int main() {
AdminPanel dashboard;
dashboard.displayStatus();
return 0;
}
Granular Access with Member Functions as Friends
Rather then granting access to an entire class, you can restrict friendship to a specific member function. This reqiures careful ordering of class declarations and definitions.
#include <iostream>
#include <string>
class HardwareVault;
class SecurityScanner {
public:
SecurityScanner();
void authorizedScan(HardwareVault* vault);
void guestScan(HardwareVault* vault);
private:
HardwareVault* targetVault;
};
class HardwareVault {
// Specifically granting access only to authorizedScan
friend void SecurityScanner::authorizedScan(HardwareVault* vault);
public:
std::string manufacturer;
HardwareVault() {
this->manufacturer = "SecureCorp";
this->firmwareVersion = "v4.0.1-Encrypted";
}
private:
std::string firmwareVersion;
};
SecurityScanner::SecurityScanner() {}
void SecurityScanner::authorizedScan(HardwareVault* vault) {
std::cout << "Manufacturer: " << vault->manufacturer << std::endl;
// Access permitted
std::cout << "Firmware: " << vault->firmwareVersion << std::endl;
}
void SecurityScanner::guestScan(HardwareVault* vault) {
std::cout << "Guest viewing: " << vault->manufacturer << std::endl;
// vault->firmwareVersion would cause a compilation error here
}
int main() {
HardwareVault vault;
SecurityScanner scanner;
std::cout << "--- Authorized Access ---" << std::endl;
scanner.authorizedScan(&vault);
std::cout << "--- Guest Access ---" << std::endl;
scanner.guestScan(&vault);
return 0;
}