Operator Overloading  «Prev  Next»
Lesson 4 Friend functions
Objective Know when (and when not) to declare a friend function, with safe modern C++ patterns.

Where (and Whether) to Declare a C++ friend Function

A friend grants a non-member function or another class access to a class’s private/protected members. This is powerful-and easy to misuse. Prefer encapsulation and narrow interfaces; introduce friendship only when it materially improves correctness or symmetry and no clean public API exists.

When Friendship Is Justified

Prefer These Alternatives First

Modern Pitfalls to Avoid

Patterns and Examples

1) Hidden friend for streaming (recommended)

Define the operator inside the class body (as a friend) but not as a member; this preserves symmetry and enables ADL without polluting the global namespace.


#include <ostream>
class Point {
  int x_ = 0, y_ = 0;

public:
  Point(int x, int y) : x_{x}, y_{y} {}

  // Hidden friend: non-member, but declared here for access + ADL.
  friend std::ostream& operator<<(std::ostream& os, const Point& p) {
    return os << '(' << p.x_ << ", " << p.y_ << ')';
  }
};

2) Non-member, non-friend using public observers (preferred when possible)

Expose a narrow observer and implement the operator without friendship.


#include <compare>

class Money {
  long long cents_ = 0; // invariant: always integral cents
public:
  explicit Money(long long cents) : cents_{cents} {}
  long long cents() const noexcept { return cents_; } // narrow observer
};

// No friend needed:
inline Money operator+(const Money& a, const Money& b) {
  return Money{a.cents() + b.cents()};
}

inline bool operator==(const Money& a, const Money& b) noexcept {
  return a.cents() == b.cents();
}

inline std::strong_ordering operator<=>(const Money& a, const Money& b) noexcept {
  return a.cents() <=> b.cents();
}

3) Member vs. friend for assignment-like operators

Operators that conceptually modify the left operand (=, [], (), ->) should be members. Return by reference where expected.


class Buffer {
  // ...
public:
  Buffer& operator=(const Buffer&) = default;     // return by reference
  Buffer& operator+=(const Buffer& rhs) { /* ... */ return *this; }
};

4) Avoid blanket class friendship

Prefer a single narrow friend function instead of friend class.


class Token {
  int kind_;
  int value_;
public:
  // Narrow friend: only the parser's exact function needs access.
  friend bool parse_token_stream(class Parser& p, Token& out);
};

Checklist Before Adding a friend

FAQ

Where do I put the declaration? Inside the class that grants access. For hidden friends, define the function inline there as well. Otherwise, declare inside, define in the same namespace as the class so ADL finds it.

Does access specifier matter? No-friend ignores public/protected/private placement. We place friends with related API (usually near observers) for discoverability.


Friend Function - Quiz

Click the Quiz link below to take a brief multiple-choice quiz on friend functions.
Friend Function - Quiz

[1]nonmember function in C++: In C++, a non-member function is a function that exists outside of any class definition. These functions operate independently of any specific object and are accessed directly by their name, without the need for a class instance or the dot operator.

SEMrush Software