Publish AI, ML & data-science insights to a global community of data professionals.

C++ Basics: Friends

In what scenarios should we use Friend in C++?

Photo by Pakata Goh on Unsplash
Photo by Pakata Goh on Unsplash

Introduction

The use of Friend in C++ is often confusing for beginners because there are a lot of arguments on the internet about whether using it will increase the encapsulation or break the encapsulation.

This is particularly true if you are new to object-oriented programming – the OOP whose main point is the concept of encapsulation which is to restrict the access to a class’s internal states by preventing other classes from accessing them.

The Friend concept in C++ is a mechanism for a class to deliberately gives other classes or functions access to its internal states. Now you can see why some people argue that this is breaking the main point of OOP.

In this post, we’ll see the Friend concept in C++, what it is for, and look at the details of how to use friend functions and friend classes. After that we’ll see in what scenarios should we use them, summarized from different sources.

Friend Concept in C++

When we declare a friend in a class, we are granting that friend access to private and protected members of the class. That means the friend can access member variables and member functions of the class.

If we don’t declare it as a friend, accessing private or protected members will result in a compilation error.

Compiling this code gives us:

In function 'void Print(const Test&)':
error: 'void Test::Print() const' is private within this context

The access rule in C++ is checked by the compiler, thus the compilation error.

In this example, the Print() function violates the access rule causing the compilation error to be thrown. To make the compilation pass, we can declare the Print() function as a friend of the Test class.

By simply adding a friend declaration we can build and execute our program which will print the numbers:

2 3

Where can I put the friend declaration?

We can put the friend declaration anywhere in the class body because the access specifier does not affect it. In the example, I put it in public but it can be anywhere.

A friend is not inherited, not transitive, and not reciprocal

In the introduction section, it’s mentioned that declaring a friend is a deliberate and explicit process. That means we have the following restrictions:

  • A friend is not inherited: children of a friend class are not friends.
  • A friend is not transitive: friends of a friend are not friends.
  • A friend is not reciprocal: I can’t access my friend’s internal states unless he/she declares me as a friend as well.

All these restrictions are there to make sure that the author of the class makes a deliberate choice whether or not to give a friend access to other classes and functions.

In the next sections, we’ll see the details of how to declare friend functions and classes.

Friend Functions

We can declare both a member function and a free function as a friend in the class body.

For a free function, it is very straightforward and a forward declaration is not required. We can simply declare the friend as follows:

The void Print(const Test& test) function has access to the private members of the Test class.

For a member function, it’s not as straightforward as the free function. Even forward declaring the class that has the function is not enough. The following will result in a compilation error.

error: invalid use of incomplete type 'class Printer'
In member function 'void Printer::Print(const Test&)':
error: 'void Test::Print() const' is private within this context

The reason is that the void Printer::Print(const Test& test) function has not been declared in the Printer class. The compiler only knows that there is a class called Printer from the forward declaration. We can fix the error by moving the Printer class up and forward declare the Test class.

Friend Classes

Not only functions, but we can also declare a class as a friend of our class. In Modern C++ there are two ways to declare a friend class:

  • friend class F;
  • friend F;

The former will declare a new class if there is no existing one and the latter will work only if the class is existing. The following code compiles without error because a new class Printer is introduced when the friend is declared.

But the following code fails because the compiler can’t find the Printer class.

error: 'Printer' does not name a type

Of course, we can simply fix this issue either by forward declaring the Printer class or changing the order of class declaration (and forward declare Test class). So the easiest solution is the former.

When should we use Friend?

Now that we understand how to correctly declare friends in C++, we need to know when we should use them.

Some of the use cases are as follows:

  • Interface Design Flexibility
  • Operator overloading

Both are for free functions, for member functions and class, the only use case I could find was for a part of Data Structure implementation (see Wikipedia for details and examples).

Interface Design Flexibility

From the example below, we have two different options to call the Print() function.

We can choose a more readable form from:

Test test(2, 3);
test.Print(); // Option 1
Print(test);  // Option 2

Some people argue that option 2 is more readable than option 1. Anyway, you have the flexibility in choosing how you want to design your interface.

Operator Overloading

The most common operator that we want to overload is the insertion operator for debugging purposes. For example:

std::cout << test;

We can’t implement this operator as a member function because the first parameter is of type std::ostream.

What about declaring unit test class as a friend class?

There are opposing opinions on this but personally, I agree with this opinion that we should only test the public interfaces.

If we found that it is difficult to cover all cases from public interfaces, it may be a sign that our class is too large and doing too many things hence we may want to refactor it.

References

Standard C++

friend (C++)

What is wrong with making a unit test a friend of the class it is testing?

Friend class – Wikipedia


Towards Data Science is a community publication. Submit your insights to reach our global audience and earn through the TDS Author Payment Program.

Write for TDS

Related Articles