- References
- Function Overloading
- Default Function Arguments
- Inline Function
- Dynamic Memory Allocation
- Placement New
- nullptr
- Namespaces
- Type Aliases
- Enum classes
- constexpr
- static_assert
- mutable Keyword
- auto Keyword
- Smart Pointers
- Basics of Classes
- Constructors
- Destructors
- Operator Overloading
- Copy Semantics
- Move Semantics
- Composition, RAII & Ownership
- Inheritance
- Polymorphism
- Abstraction
- Encapsulation
- Template
- Static Memory
- Friend Function
- this Pointer
- Function Pointer
- Lambdas and Callback Management
- Union
Friend Functions (Controlled Access)

In C++, private data is like a vault—locked away from the outside world. Only the class's own member functions have the key.
A Friend Function is a special function that is not a member of the class, yet it is granted a "Special Key" to access private and protected members.
The Golden Rule: Friendship is granted, not taken. The class itself must explicitly say "Function X is my friend."
Analogy:
Public: Your front porch. Anyone can stand there.
Private: Your living room. Only you (Member Functions) have the key.
Friend: Your trusted neighbor. They don't live there (Not a member), but you gave them a spare key so they can enter your living room.
Syntax & Usage
To create a friend, you declare the function inside the class with the friend keyword, but you define it outside like a normal C function.
class Box {
private:
int width;
public:
Box(int w) : width(w) {}
// 1. Declaration: "printWidth is allowed to touch my private data."
// Note: It is NOT a member function.
friend void printWidth(Box& b);
};
// 2. Definition: Note there is NO "Box::" scope resolution.
// It is just a normal global function.
void printWidth(Box& b) {
// Normal function: b.width would be an error.
// Friend function: b.width is ALLOWED.
printf("Width: %d\n", b.width);
}
int main() {
Box box(10);
printWidth(box); // Called like a standard C function
}The "Killer Use Case": Operator Overloading
This is the #1 reason we use Friend Functions in C++.
If you want to support cout << object, you cannot use a member function.
Why?
Member functions require the object to be on the left (
obj.func()).In
cout << obj, thecoutobject is on the left.Therefore, we need a global function that takes
(cout, obj)as arguments. To print the object's internals, this global function must be a Friend.
class Sensor {
private:
int value;
public:
Sensor(int v) : value(v) {}
// Friend allows 'operator<<' to read private 'value'
friend std::ostream& operator<<(std::ostream& os, const Sensor& s);
};
// Global function definition
std::ostream& operator<<(std::ostream& os, const Sensor& s) {
os << "Sensor Value: " << s.value; // Direct private access
return os;
}
// Usage
Sensor s(42);
std::cout << s << std::endl; // Works beautifully!Dual Access (The Bridge)
Sometimes, a function needs to operate on two different classes at once. A member function belongs to only one class. A friend function can be a friend to both.
class Square; // Forward Declaration
class Rectangle {
int width, height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
friend void compare(Rectangle r, Square s);
};
class Square {
int side;
public:
Square(int s) : side(s) {}
friend void compare(Rectangle r, Square s);
};
// This function can touch privates of BOTH classes
void compare(Rectangle r, Square s) {
int area_r = r.width * r.height; // Access Rectangle private
int area_s = s.side * s.side; // Access Square private
// ... compare logic ...
}
Relevance in Embedded/Firmware
1. Hardware Abstraction (HAL) Testing
When writing Unit Tests (e.g., GoogleTest) on a PC, you often need to check the internal state of a driver (e.g., "Did the internal_buffer_index reset to 0?").
Instead of making internal_buffer_index public (unsafe), you make the Test Class a friend.
friend class SensorTest;
2. Interrupt Service Routines (ISRs)
ISRs are standard C functions (or static methods). They cannot be normal member functions.
If an ISR needs to reset a private flag inside a global object, making the ISR a Friend is a clean way to give it access without exposing the flag to the whole world.
Common Pitfalls (The "Friend Zone" Rules)
Rule | Explanation |
|---|---|
Not Mutual | If Class A is a friend of B, B is not automatically a friend of A. (Just because I trust you doesn't mean you trust me). |
Not Inherited | If Base class has a friend, the Derived class does not inherit that friend. (My father's friends are not automatically my friends). |
No | Since a friend function is not a member, it has no this pointer. You must pass the object explicitly as an argument (void func(MyClass& obj)). |
Breaks Encapsulation | Overusing friends defeats the purpose of OOP. If you have 10 friend functions, your class is basically public. Use sparingly! |
Summary Checklist
Use
friendkeyword inside the class.Do not use
Class::when defining the function.Use primarily for
operator<<or bridging two classes.Remember: It allows access to private and protected members.
Concept understood? Let's apply and learn for real