Master C++ friend: 5 Levels of Usage Every Interview Candidate Should Know

This article walks through the five practical levels of using C++ friend— from a quick syntax recap to operator overloads, factory functions, iterator access, swap idiom, and the Passkey pattern—explaining when and why each scenario warrants a friend declaration and how it impacts encapsulation and interview performance.

IT Services Circle
IT Services Circle
IT Services Circle
Master C++ friend: 5 Levels of Usage Every Interview Candidate Should Know

Level 0: 30‑second friend syntax recap

Friend can be declared as a friend function or a friend class . The function gains access to private members, while the whole class is granted that privilege.

class MyClass {
    int secret_ = 42;
    // friend function
    friend void peek(const MyClass& obj);
    // friend class
    friend class OtherClass;
};

void peek(const MyClass& obj) {
    std::cout << obj.secret_ << std::endl; // OK, friend function can access
}

The core idea is that friend is a directional authorization —it gives a specific function or class access to private members without exposing them publicly.

C++11 added two extensions: you can omit the class keyword when declaring a friend class, and you can make a template parameter a friend.

template<typename T> class Container {
    friend T; // C++11 only
    int data_;
};

Level 1: operator<< and operator>> overloads

The classic interview scenario: overloading operator<< for output. Because the left operand is an ostream, the overload must be a non‑member function, yet it needs to read private data. Declaring it as a friend solves this.

class Point {
    double x_, y_;
public:
    Point(double x, double y) : x_(x), y_(y) {}
    friend std::ostream& operator<<(std::ostream& os, const Point& p) {
        return os << "(" << p.x_ << ", " << p.y_ << ")";
    }
};

Using a public getter would expose every member to everyone; a friend keeps the encapsulation tighter.

Level 2: Factory functions and private constructors

When a class hides its constructor to control creation, a factory function needs to call that private constructor. Making the factory a friend grants it the required access.

class DatabaseConnection {
    std::string host_;
    int port_;
    DatabaseConnection(const std::string& host, int port) : host_(host), port_(port) {}
    friend DatabaseConnection createConnection(const std::string& config);
};

DatabaseConnection createConnection(const std::string& config) {
    // parse config …
    return DatabaseConnection("localhost", 3306);
}

A similar pattern appears in Singleton variants where the base class must invoke a private constructor of a derived class, so the base is declared as a friend of the derived.

Level 3: Iterator ↔ container relationship

Custom containers often need iterators that walk internal nodes. Exposing those nodes via public getters would break encapsulation, so the container declares the iterator class as a friend.

template<typename T> class MyListIterator;

template<typename T> class MyList {
    struct Node { T data; Node* next; };
    Node* head_ = nullptr;
    friend class MyListIterator<T>;
public:
    using iterator = MyListIterator<T>;
    iterator begin() { return iterator(head_); }
    iterator end()   { return iterator(nullptr); }
};

template<typename T> class MyListIterator {
    typename MyList<T>::Node* current_;
public:
    explicit MyListIterator(typename MyList<T>::Node* node) : current_(node) {}
    T& operator*() { return current_->data; }
    MyListIterator& operator++() { current_ = current_->next; return *this; }
    bool operator!=(const MyListIterator& other) const { return current_ != other.current_; }
};

The rule of thumb: use a friend class when two classes are two views of the same abstraction (container vs iterator).

Level 4: friend swap – the hidden best practice

Declaring a non‑member swap as a friend enables Argument‑Dependent Lookup (ADL) to find the efficient, field‑wise swap used by the copy‑and‑swap idiom.

class Buffer {
    size_t size_;
    char* data_;
public:
    Buffer(size_t size) : size_(size), data_(new char[size]) {}
    ~Buffer() { delete[] data_; }
    friend void swap(Buffer& a, Buffer& b) noexcept {
        using std::swap;
        swap(a.size_, b.size_);
        swap(a.data_, b.data_);
    }
    Buffer& operator=(Buffer other) {
        swap(*this, other);
        return *this;
    }
};

Because standard algorithms use using std::swap; swap(a,b);, a member swap would be ignored by ADL and fall back to the generic three‑move version, which is slower.

Level 5: Passkey idiom – fine‑grained replacement for friend

Friend grants access to *all* private members, which can be too broad. The Passkey pattern introduces a tiny “key” class that only the authorized creator can construct, allowing selective access.

class FactoryKey {
    friend class Factory;
    FactoryKey() {}
    FactoryKey(const FactoryKey&) = default;
};

class Widget {
public:
    Widget(int value, FactoryKey) : value_(value) {}
private:
    int value_;
};

class Factory {
public:
    static Widget create(int value) {
        return Widget(value, FactoryKey{}); // only Factory can make the key
    }
};

The constructor remains public (so IDEs show it), but without a valid FactoryKey the call is ill‑formed, achieving function‑level access control.

When to choose friend function vs friend class

Use a friend function when only a single function needs access; use a friend class when an entire class’s multiple methods need to see the internals. Prefer the smaller scope of a friend function to avoid over‑exposing internals.

Summary of the five levels

L0 : Quick syntax recap – friend function vs friend class.

L1 : Operator overloads ( operator<<, operator>>) that must be non‑member but need private access.

L2 : Factory functions / Singleton – private constructors accessed via friend.

L3 : Container ↔ iterator – friend class for tightly coupled dual‑view designs.

L4 : Friend swap – enables ADL and efficient copy‑and‑swap.

L5 : Passkey idiom – fine‑grained, function‑level access control as a refined alternative to broad friend classes.

If a candidate can walk through these levels and explain why each scenario needs a friend, the interview question turns from a trivial point‑score into a strong differentiator.

声明:本文是经过严格查阅相关权威文献和资料,形成的专业的可靠的内容。全文数据都有据可依,可回溯。特别申明:数据和资料已获得授权。本文内容,不涉及任何偏颇观点,用中立态度客观事实描述事情本身。
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Design PatternsAccess ControlCfriend
IT Services Circle
Written by

IT Services Circle

Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.