Article by Ayman Alheraki on January 21 2026 03:04 PM
friend ExistsC++ is built on strong encapsulation.
By default, an object’s internals are hidden behind private and protected access specifiers.
Yet real systems often require trusted collaboration between tightly related components.
The friend mechanism exists to solve a precise problem:
Grant explicit, targeted, and non-hierarchical access to otherwise private internals.
Unlike inheritance or public APIs, friend is:
Explicit
Non-transitive
Non-inheritable
One-directional
Used correctly, it enables clean architecture. Used poorly, it destroys encapsulation.
friend in C++?A friend is a function or class that is allowed to access private and protected members of another class.
Key properties:
| Property | Behavior |
|---|---|
| Access | Can access private and protected members |
| Scope | Friendship is not reciprocal |
| Inheritance | Friendship is not inherited |
| Polymorphism | Friendship is not virtual |
| Ownership | Friend is not a member |
class Secret {private: int value = 42;
friend void reveal(const Secret&);};
void reveal(const Secret& s) { std::cout << s.value << '\n';}Important points:
reveal is not a member function
It has full access to private members
Friendship is granted explicitly inside the class
This is the most legitimate and common use of friend.
class Vec2 {private: float x, y;
public: Vec2(float x, float y) : x(x), y(y) {}
friend Vec2 operator+(const Vec2& a, const Vec2& b);};
Vec2 operator+(const Vec2& a, const Vec2& b) { return { a.x + b.x, a.y + b.y };}Reasons for using friend:
Operators must be symmetric
The operator cannot belong to both operands
Avoids unnecessary getters that weaken encapsulation
<<, >>)Canonical example:
class User { std::string name; int age;
public: friend std::ostream& operator<<(std::ostream&, const User&);};
std::ostream& operator<<(std::ostream& os, const User& u) { return os << u.name << " (" << u.age << ")";}This preserves encapsulation, natural syntax, and performance.
class Engine;
class Car {private: int horsepower = 300;
friend class Engine;};
class Engine {public: void tune(Car& c) { c.horsepower += 50; }};Key observations:
The entire Engine class gains access
Friendship is one-directional
No inheritance relationship exists
Friend classes are justified when:
Two classes are conceptually inseparable
One class provides infrastructure for another
Performance prohibits public accessors
Typical examples:
Iterator and container implementations
Serializer and domain object
Memory allocator and object layout
ORM mapper and entity
This distinction is fundamental.
| Feature | friend | Inheritance |
|---|---|---|
| Access | Full | Controlled |
| Relationship | Trust-based | Is-a |
| Polymorphism | No | Yes |
| Substitutability | No | Yes |
| Transitivity | No | Yes |
If a design implies an is-a relationship, friend is the wrong tool.
friendModern C++ encourages non-member, non-friend functions whenever possible.
Use friend only when:
Accessors would expose invariants
Performance matters
Symmetric operations are required
Poor practice:
xxxxxxxxxxfriend class Everything;
Better practice:
xxxxxxxxxxfriend void serialize(const Foo&);
Rule: Grant the smallest possible friend.
friend as an Architectural BoundaryIn well-designed systems, friend often marks:
Internal subsystems
Trusted infrastructure layers
Explicit encapsulation boundaries
This pattern appears in:
The C++ Standard Library
Compilers and toolchains
Game engines
Embedded and real-time systems
friend and Modern C++ Featurestemplate<typename T>class Box { T value;
template<typename U> friend class Inspector;};Function template friendship:
template<typename T>class Data { T value;
template<typename U> friend void inspect(const Data<U>&);};This is powerful but must be tightly controlled.
constexprFriends fully participate in compile-time evaluation.
class ConstValue { int v;
friend constexpr int get(const ConstValue& c) { return c.v; }};Modules do not change friend semantics.
Important notes:
Friendship does not bypass module visibility rules
The friend must still be visible within the module interface or implementation
Modules improve encapsulation but do not weaken access control.
Using friend to avoid proper design
Granting friendship to large subsystems
Replacing interfaces with friend
Treating friend as unrestricted access
friend Is the Right ToolUse friend when:
Two entities form a single conceptual unit
Zero-overhead access is required
Symmetric non-member operations are needed
Explicit trust is preferable to inheritance
Avoid friend when:
A public API is sufficient
Inheritance models the relationship
Access can be restricted through interfaces
friend is not a shortcut.
It is a precision tool.
In Modern C++:
It enables zero-cost abstractions
It supports correct operator design
It preserves encapsulation with deliberate exceptions
Strong engineers do not avoid friend.
They use it deliberately and sparingly.