C++ OOP
Friend Functions & Classes
Complete lesson for Friend Functions & Classes using LEARNCODEGURU’s 6-level learning model — from basics to advanced practice, with C++ OOP and STL where relevant.
Basics — Friend Functions & Classes
Section: C++ OOP. C++ friend functions and friend classes — selective private access, rules, and when to use them.
What is a friend in C++?
- A **friend** is a function or class granted permission to access another class’s **private** and **protected** members.
- Declared with the
friendkeyword inside the class that opens its private data. - Friendship is a **selective hole** in encapsulation — useful, but use carefully.
- **Real-life:** a locked diary (private data). A friend is allowed to read it; strangers are not.
- **Real-life:** bank vault — only authorized staff (friends) may enter, not every customer.
| Idea | Meaning | Example |
|---|---|---|
friend function | Non-member with private access | friend void show(const Box&); |
friend class | All members of that class get access | friend class Auditor; |
| Declared where? | Inside the granting class | In private/public section (same effect) |
| Still not a member | No this of the granting class | Pass objects as parameters |
Friend function
- A normal function (or another class’s member) marked
friendcan touch private data. - It is **not** called like
obj.friendFunc()as a member — call it as a free function (unless it is a member of another class). - Often used for operators that need symmetry:
operator<<,operator+between two types.
#include <iostream>
using namespace std;
class Box {
private:
int width, height;
public:
Box(int w, int h) : width(w), height(h) {}
friend void printArea(const Box& b); // friend function
};
void printArea(const Box& b) {
cout << "Area = " << (b.width * b.height) << "\n"; // OK — friend
}
int main() {
Box b(4, 5);
printArea(b);
// cout << b.width; // ERROR — private
return 0;
} Friend class
- If
class A { friend class B; };then **all** member functions ofBcan accessA’s private/protected members. - Useful when two types are tightly coupled (e.g.
MatrixandMatrixHelper,NodeandLinkedList). - **Real-life:** hospital Patient records — Doctor class is a friend department with full chart access.
#include <iostream>
#include <string>
using namespace std;
class Patient {
private:
string name;
int heartRate;
public:
Patient(string n, int hr) : name(n), heartRate(hr) {}
friend class Doctor;
};
class Doctor {
public:
void checkup(const Patient& p) {
cout << p.name << " HR=" << p.heartRate << "\n"; // OK — friend class
}
};
int main() {
Patient p("Ravi", 72);
Doctor d;
d.checkup(p);
return 0;
} Rules of friendship (important)
- Friendship is **not mutual**:
Afriend ofBdoes not makeBfriend ofAautomatically. - Friendship is **not inherited**: derived classes do not inherit friendship.
- Friendship is **not transitive**: friend of a friend is not a friend.
- A friend declaration can appear in any access section — access level of the declaration does not change friendship.
| Rule | Meaning | Example thought |
|---|---|---|
| Not mutual | One-way grant | A opens to B; B stays closed to A |
| Not inherited | Child ≠ friend | Base friends X; Derived does not |
| Not transitive | No chain | A→B and B→C does not imply A→C |
| Selective | You choose exactly who | Prefer few, clear friends |
Member function vs friend function
- Both can access private data if designed that way — different calling styles and design roles.
| Point | Member function | Friend function |
|---|---|---|
| Belongs to class? | Yes | No (usually free function) |
Has this? | Yes | No (unless member of another class) |
| Call style | obj.f() | f(obj) or a + b |
| Private access | Yes (own class) | Yes if declared friend |
| Good for | Object behaviour | Symmetric operators, helpers |
Classic use — operator<< as friend
- Left operand of
<<is usuallyostream&, not your class — so a memberoperator<<on your class is awkward. - A **friend** (or free function with public getters) lets you write
cout << obj;. - Prefer getters when they are enough; use friend when you need deep private access cleanly.
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
int roll;
string name;
public:
Student(int r, string n) : roll(r), name(n) {}
friend ostream& operator<<(ostream& os, const Student& s);
};
ostream& operator<<(ostream& os, const Student& s) {
os << s.roll << " " << s.name;
return os;
}
int main() {
Student s(101, "Asha");
cout << s << "\n";
return 0;
} When to use friend (and when not)
- Friends weaken encapsulation — grant them only when the design truly needs private access.
| Situation | Prefer | Why |
|---|---|---|
| Symmetric binary operators | Friend / free function | Natural a + b / cout << a |
| Tight helper of one class | Friend function/class | Needs internals |
| Normal behaviour of object | Public member function | Keeps encapsulation |
| Just reading a field | Public getter | No need for friend |
| Many outsiders need data | Rethink API | Too many friends = leaky design |
Advanced — Friend Functions & Classes
Friend member function of another class
- You can friend a **specific** member function:
friend void Other::peek(const My&); - Requires careful declaration order / forward declarations.
- Narrower than friending the whole class — better for encapsulation.
Forward declarations and friend
- Often you forward-declare a class before friending it:
class Auditor; class Account { friend class Auditor; ...}; - Circular friendships need careful header structure.
class Doctor; // forward declaration
class Patient {
int id;
friend class Doctor;
public:
Patient(int i) : id(i) {}
}; Friendship and encapsulation trade-off
- Every friend is an exception to data hiding.
- Document why friendship exists.
- If many friends appear, the class may need a better public interface or to split responsibilities.
- Operators and tightly coupled containers/nodes are the most accepted friend uses.
Common pitfalls
- Assuming friendship is mutual or inherited — it is not.
- Friending an entire class when one function would do.
- Using friend to avoid writing a clean API.
- Forgetting that friend functions still need proper declarations/definitions.
Real-life models
- Hospital:
PatientfriendsDoctor. - Bank:
AccountfriendsAuditorfor inspection. - Game:
GameObjectfriendsPhysicsEnginefor private transform access. - Containers:
ListfriendsListIterator/ node helpers.
Tricky Interview Points
Q1) What is a friend function?
Answer A non-member function granted access to a class’s private and protected members via a friend declaration inside that class.
Q2) What is a friend class?
Answer A class whose member functions can access another class’s private/protected members because it was declared as a friend.
Q3) Is friendship mutual?
Answer No. If A declares B as a friend, B does not automatically become able to have A as a friend the other way.
Q4) Is friendship inherited?
Answer No. Friendship is not inherited by derived classes.
Q5) Is friendship transitive?
Answer No. Friend of a friend is not automatically a friend.
Q6) Why use friend for operator<<?
Answer Because the left operand is typically ostream, so a free/friend function fits naturally for cout << obj while allowing private access if needed.
Q7) Does a friend function have a this pointer of the granting class?
Answer No. It is not a member of that class, so it receives objects as explicit parameters.
Q8) Where should friend be declared?
Answer Inside the class that grants access. The access section (private/public) does not change the friendship grant.
Q9) When should you avoid friends?
Answer When a public method or getter is enough, or when many friends would punch too many holes in encapsulation.
Q10) Member function vs friend function?
Answer Members are part of the class and use this; friends are outside (usually) but can access privates if granted. Friends are handy for symmetric operators.
Q11) Can we friend only one member function of another class?
Answer Yes — you can declare a specific Other::func as friend instead of the whole class.
Q12) Give a real-life analogy for friend.
Answer A locked diary that only named friends may read; friendship is granted by the owner and is not automatically two-way.
Simple Programs
Friend function — print private data
#include <iostream>
using namespace std;
class Secret {
private:
int code;
public:
Secret(int c) : code(c) {}
friend void reveal(const Secret& s);
};
void reveal(const Secret& s) {
cout << "code = " << s.code << "\n";
}
int main() {
Secret s(42);
reveal(s);
return 0;
} Friend class — Doctor / Patient
#include <iostream>
#include <string>
using namespace std;
class Patient {
string name;
int hr;
public:
Patient(string n, int h) : name(n), hr(h) {}
friend class Doctor;
};
class Doctor {
public:
void report(const Patient& p) {
cout << p.name << ": " << p.hr << " bpm\n";
}
};
int main() {
Patient p("Neha", 78);
Doctor().report(p);
return 0;
} Friendship is not mutual
#include <iostream>
using namespace std;
class A {
private:
int x = 1;
public:
friend class B; // B may access A
};
class B {
private:
int y = 2;
public:
void showA(const A& a) { cout << a.x << "\n"; } // OK
// A cannot access y unless B also declares friend class A;
};
int main() {
A a; B b;
b.showA(a);
return 0;
} operator<< as friend
#include <iostream>
using namespace std;
class Point {
int x, y;
public:
Point(int a, int b) : x(a), y(b) {}
friend ostream& operator<<(ostream& os, const Point& p);
};
ostream& operator<<(ostream& os, const Point& p) {
return os << "(" << p.x << "," << p.y << ")";
}
int main() {
Point p(2, 3);
cout << p << "\n";
return 0;
} Compare — getter vs friend
#include <iostream>
using namespace std;
class Temp {
private:
int c = 25;
public:
int getC() const { return c; }
friend void showFriend(const Temp& t);
};
void showFriend(const Temp& t) { cout << t.c << "\n"; }
void showGetter(const Temp& t) { cout << t.getC() << "\n"; }
int main() {
Temp t;
showFriend(t);
showGetter(t);
return 0;
} Binary friend operator+
#include <iostream>
using namespace std;
class Vec2 {
int x, y;
public:
Vec2(int a, int b) : x(a), y(b) {}
friend Vec2 operator+(const Vec2& a, const Vec2& b);
void show() const { cout << x << "," << y << "\n"; }
};
Vec2 operator+(const Vec2& a, const Vec2& b) {
return Vec2(a.x + b.x, a.y + b.y);
}
int main() {
Vec2 u(1, 2), v(3, 4);
Vec2 w = u + v;
w.show(); // 4,6
return 0;
} Problem Solving Tricks
- friend grants private/protected access — a controlled exception to encapsulation.
- Remember: not mutual, not inherited, not transitive.
- Prefer friending one function over an entire class when possible.
- operator<< / symmetric operators are classic friend use cases.
- If a getter is enough, skip friend.
- Friends are not members — no this of the granting class.
- Document why each friend exists.
- Too many friends ⇒ redesign the public API.
- Forward-declare classes involved in friendship when needed.
- Friend declaration’s private/public section does not limit the grant.
- Use const references in friend helpers that only read.
- Diary/vault analogies work well in interviews.
Practice Programs List
- Write a Box class with private width/height and a friend printArea function.
- Create Patient and friend class Doctor that prints private vitals.
- Demonstrate that friendship is not mutual with two small classes.
- Implement operator<< as a friend for a Student class.
- Implement operator+ as a friend for a Complex or Vec2 class.
- Refactor a friend that only reads one field into a public getter instead.
- Friend a single member function of another class (advanced ordering exercise).
- Explain in comments the three friendship rules with tiny examples.
- Build Account with friend Auditor::inspect.
- Compare member display() vs friend display(obj) calling styles.
- List five designs where friend is justified and five where it is not.
- Show a compile error when a non-friend tries to access private data.
- Write LinkedList friending Node (or vice versa) for a mini list demo.
- Discuss encapsulation trade-offs of your friend usage in comments.