C++98corebeginner
Friend Classes
C++98 · The Foundation · Compiler flag: -std=c++98
Explanation
A class granted access to another class’s private members.
Real-World Scenario
A renderer class accessing private data of a game object.
Quick Snippet
snippet.cpp
class GameObject { friend class Renderer; };Full Example
friend_classes.cpp
// CodeNebula - C++98 Example: Friend Classes
// Compile: g++ -std=c++98 -Wall -Wextra -o example friend_classes.cpp
//
// This example demonstrates:
// - Declaring an entire class as a friend
// - The friend class can access all private/protected members
// - Friendship is one-directional (A friends B != B friends A)
// - Friendship is NOT inherited by derived classes
// - Practical use cases: Iterator pattern, Builder pattern
#include <iostream>
#include <cstring>
// ============================================================
// 1. Basic friend class: Engine and Mechanic
// ============================================================
class Engine {
private:
int horsepower;
double temperature;
bool running;
// Only Mechanic (and Engine itself) can see internals
friend class Mechanic;
public:
Engine(int hp) : horsepower(hp), temperature(20.0), running(false) {}
void start() {
running = true;
temperature = 90.0;
std::cout << " Engine started (" << horsepower << " HP)" << std::endl;
}
void stop() {
running = false;
temperature = 20.0;
std::cout << " Engine stopped" << std::endl;
}
// Public interface -- limited info
bool isRunning() const { return running; }
};
class Mechanic {
private:
char name[32];
public:
Mechanic(const char* n) {
std::strncpy(name, n, 31);
name[31] = '\0';
}
// Can access ALL private members of Engine
void diagnose(const Engine& e) const {
std::cout << " Mechanic " << name << " diagnosing engine:" << std::endl;
std::cout << " Horsepower: " << e.horsepower << std::endl;
std::cout << " Temperature: " << e.temperature << " C" << std::endl;
std::cout << " Running: " << (e.running ? "yes" : "no") << std::endl;
}
void tuneUp(Engine& e) const {
std::cout << " Mechanic " << name << " tuning engine..." << std::endl;
e.horsepower += 10; // direct access to private member
std::cout << " New horsepower: " << e.horsepower << std::endl;
}
};
// ============================================================
// 2. Friendship is ONE-DIRECTIONAL
// ============================================================
class ClassA {
private:
int secretA;
friend class ClassB; // ClassB can access ClassA's privates
public:
ClassA(int v) : secretA(v) {}
void tryAccessB() const {
// ClassB b(99);
// b.secretB; // ERROR: ClassA is NOT a friend of ClassB
std::cout << " ClassA CANNOT access ClassB's privates" << std::endl;
}
};
class ClassB {
private:
int secretB;
public:
ClassB(int v) : secretB(v) {}
void accessA(const ClassA& a) const {
// ClassB IS a friend of ClassA -- can access secretA
std::cout << " ClassB accesses ClassA's secretA = " << a.secretA << std::endl;
}
};
// ============================================================
// 3. Friendship is NOT inherited
// ============================================================
class Secret {
private:
int value;
friend class Trusted;
public:
Secret(int v) : value(v) {}
};
class Trusted {
public:
void access(const Secret& s) const {
std::cout << " Trusted accesses Secret value = " << s.value << std::endl;
}
};
class UntrustedChild : public Trusted {
public:
void tryAccess(const Secret& s) const {
// s.value; // ERROR: friendship is NOT inherited
// UntrustedChild is NOT a friend of Secret
(void)s; // suppress unused warning
std::cout << " UntrustedChild CANNOT access Secret value" << std::endl;
}
};
// ============================================================
// 4. Practical: LinkedList with friend Iterator
// ============================================================
class LinkedList {
private:
struct Node {
int data;
Node* next;
Node(int d, Node* n) : data(d), next(n) {}
};
Node* head;
int count;
friend class ListIterator; // Iterator needs access to Node
public:
LinkedList() : head(NULL), count(0) {}
~LinkedList() {
Node* current = head;
while (current != NULL) {
Node* next = current->next;
delete current;
current = next;
}
}
void pushFront(int value) {
head = new Node(value, head);
++count;
}
int size() const { return count; }
void print() const {
std::cout << " [";
Node* n = head;
while (n != NULL) {
if (n != head) std::cout << " -> ";
std::cout << n->data;
n = n->next;
}
std::cout << "]" << std::endl;
}
};
class ListIterator {
private:
LinkedList::Node* current; // accesses private Node type
public:
ListIterator(const LinkedList& list) : current(list.head) {} // accesses private head
bool hasNext() const {
return current != NULL;
}
int next() {
int val = current->data; // accesses private Node::data
current = current->next;
return val;
}
void reset(const LinkedList& list) {
current = list.head;
}
};
int main() {
std::cout << "========================================" << std::endl;
std::cout << "1. BASIC FRIEND CLASS (Engine & Mechanic)" << std::endl;
std::cout << "========================================" << std::endl;
{
Engine e(200);
Mechanic m("Bob");
m.diagnose(e);
std::cout << std::endl;
e.start();
m.diagnose(e);
std::cout << std::endl;
m.tuneUp(e);
m.diagnose(e);
}
std::cout << "\n========================================" << std::endl;
std::cout << "2. FRIENDSHIP IS ONE-DIRECTIONAL" << std::endl;
std::cout << "========================================" << std::endl;
{
ClassA a(42);
ClassB b(99);
b.accessA(a); // OK: ClassB is friend of ClassA
a.tryAccessB(); // ClassA is NOT friend of ClassB
}
std::cout << "\n========================================" << std::endl;
std::cout << "3. FRIENDSHIP IS NOT INHERITED" << std::endl;
std::cout << "========================================" << std::endl;
{
Secret s(777);
Trusted t;
UntrustedChild uc;
t.access(s); // OK: Trusted is a friend
uc.tryAccess(s); // NOT OK: friendship not inherited
}
std::cout << "\n========================================" << std::endl;
std::cout << "4. PRACTICAL: LINKED LIST + ITERATOR" << std::endl;
std::cout << "========================================" << std::endl;
{
LinkedList list;
list.pushFront(30);
list.pushFront(20);
list.pushFront(10);
std::cout << " List: ";
list.print();
std::cout << " Size: " << list.size() << std::endl;
std::cout << " Iterating with ListIterator:" << std::endl;
ListIterator it(list);
std::cout << " ";
while (it.hasNext()) {
std::cout << it.next() << " ";
}
std::cout << std::endl;
// Sum using iterator
it.reset(list);
int sum = 0;
while (it.hasNext()) {
sum += it.next();
}
std::cout << " Sum = " << sum << std::endl;
}
std::cout << "\n========================================" << std::endl;
std::cout << "5. SUMMARY" << std::endl;
std::cout << "========================================" << std::endl;
std::cout << " - 'friend class X;' grants X full access to private members" << std::endl;
std::cout << " - One-directional: A friends B does NOT mean B friends A" << std::endl;
std::cout << " - NOT inherited: child of friend is NOT a friend" << std::endl;
std::cout << " - NOT transitive: friend of friend is NOT a friend" << std::endl;
std::cout << " - Use sparingly: tight coupling, but sometimes necessary" << std::endl;
std::cout << " - Common uses: iterators, builders, serializers, test classes" << std::endl;
return 0;
}
// Expected output:
// ========================================
// 1. BASIC FRIEND CLASS (Engine & Mechanic)
// ========================================
// Mechanic Bob diagnosing engine:
// Horsepower: 200
// Temperature: 20 C
// Running: no
//
// Engine started (200 HP)
// Mechanic Bob diagnosing engine:
// Horsepower: 200
// Temperature: 90 C
// Running: yes
//
// Mechanic Bob tuning engine...
// New horsepower: 210
// ...
//
// ========================================
// 2. FRIENDSHIP IS ONE-DIRECTIONAL
// ========================================
// ClassB accesses ClassA's secretA = 42
// ClassA CANNOT access ClassB's privates
//
// ========================================
// 3. FRIENDSHIP IS NOT INHERITED
// ========================================
// Trusted accesses Secret value = 777
// UntrustedChild CANNOT access Secret value
//
// ========================================
// 4. PRACTICAL: LINKED LIST + ITERATOR
// ========================================
// List: [10 -> 20 -> 30]
// Size: 3
// Iterating with ListIterator:
// 10 20 30
// Sum = 60
Run command
g++ -std=c++98 -Wall -Wextra -o example friend_classes.cpp