C++

C++ - Friends

Friend Class, Friend Function, Inner Class

Posted by Rico's Nerd Cluster on February 28, 2023

In C++, friend functions and friend classes provide controlled access to private members of a class. While useful, they should be used judiciously to maintain encapsulation and avoid unnecessary dependencies. Let’s explore their roles and best practices.

friend Functions

A friend function allows external functions to access the private and protected members of a class without being a member function itself. A friend function has the same privilege level as a member function but is not bound to a specific object instance.

Best Practice: Place friend Functions at the Top of the Class Definition

Unlike member functions, friend functions do not require public or private access specifiers. A common convention is to place them at the beginning of the class definition, near the public section for clarity.

1
2
3
4
5
class Foo {
    friend std::istream& operator>>(std::istream&, Foo&);
public:
    // Other members
};

When a friend Function - Accessor, and Overloading

Sometimes, making a function friend is unnecessary. For example:

  • Can I add std::istream & operator>>(std::istream & is, Transform2D & tf); as a friend function to Transform2D so I can modify its private Matrix values?

The answer: No, you don’t need to. In this case, a simple overloaded function can achieve the same result.

friend Classes

A friend class can access all private and protected members of another class. This is useful in cases where a separate class requires intimate knowledge of another’s implementation. (So this is even more “intimate” than a child class)

Example: Granting Student_Handle Access to Core: by declaring Student_Handle as a friend of Core, all member functions of Student_Handle can access Core’s private and protected members.

1
2
3
class Core {
    friend class Student_Handle;
};

Important Considerations

  • Friendship is Not Mutual:
    • Unless explicitly specified, if Class A declares Class B as a friend, Class B does not automatically consider Class A a friend.
  • Friendship is Not Inherited:
    • If Core has a friend class, its derived classes do not automatically inherit this friendship, unless explicitly declared.
  • Friendship is Not Transitive:
    • A friend of a friend does not gain access. E.g., if Class A grants Class B access, Class B cannot pass this privilege to Class C.

Inner (Nested) Classes

A nested class is defined within another class, making it an inner class. By default, an inner class is implicitly a friend of its enclosing class, meaning it can access private members.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Enclosing {
private:
    int x = 30;  // Private member
public:
    class Nested {
    public:
        void nested_func(Enclosing* e) {
            cout << e->x;  // Allowed: Nested class can access private members of Enclosing
        }
    };
    Nested n_;  // Nested must be declared
    void func() {
        n_.nested_func(this);
    }
};
  • Therefore, access modifiers do not matter: The inner class can be declared in the private, protected, or public section of the enclosing class—it still has access to private members.
  • The Nested Class Must Be Declared First: To use a nested class inside the enclosing class, it must be declared before being instantiated.