Friend Functions (Controlled Access)

cardimg

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, the cout object 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 this Pointer

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 friend keyword 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

Practice now