A friend non-member function is a non-member function which has access to private and protected members (public are always accessible). A class declaring a non-member function a friend, gives the control to access the members to the function.
Apart from friend non-member functions, we can also create friend member functions and friend classes. I would be using just friend functions for friend non-member functions in subsequent sections.
Defining a friend non-member function
A non-member function has to be declare in the class using friend keyword and can either be defined outside or inside the class (I would prefer defining outside as that would make more sense).
For example:
#include <iostream>
class Point
{
private:
int m_x{};
int m_y{};
public:
Point() = default;
constexpr Point(int x, int y)
: m_x{x}, m_y{y}
{
}
friend void print(const Point &p);
};
void print(const Point &p)
{
std::cout << "Point {" << p.m_x << ", " << p.m_y << "}\n";
}
int main(int argc, char const *argv[])
{
Point p{1, 2};
print(p);
return 0;
}We declared friend function print. As it is a non-member function, we need to explicitly pass Point object. We then defined the friend function outside as usual non-member function. We can use private member of the class int print function as class has made print its friend.
Example of defining friend function inside the class:
class Point
{
private:
int m_x{};
int m_y{};
public:
Point() = default;
constexpr Point(int x, int y)
: m_x{x}, m_y{y}
{
}
friend void print(const Point &p)
{
std::cout << "Point {" << p.m_x << ", " << p.m_y << "}\n";
}
};Although print is defined inside the class, it does not make it a member function.
Friend to multiple classes
It is possible for a function to be friend to multiple classes. For example:
// I could not find a good example, so using dummy names for classes.
class B; // forward declaration
class A
{
int m_value{};
public:
A() = default;
A(int value)
: m_value{value}
{
}
// using B's forward declaration here
friend void printAB(const A &a, const B &b);
};
class B
{
int m_value{};
public:
B() = default;
B(int value)
: m_value{value}
{
}
friend void printAB(const A &a, const B &b);
};
void printAB(const A &a, const B &b)
{
std::cout << "A{" << a.m_value << "}\n";
std::cout << "B{" << b.m_value << "}\n";
}
int main(int argc, char const *argv[])
{
A a{1};
B b{2};
printAB(a, b);
return 0;
}printAB is declared as friend to both classes A and B and defined outside as it does not make any sense of defining in any of these classes.
We need forward declaration for class B to let compiler know about the class. Forward declaration of class only requires class and class name.
As an aside
One might say, are friend functions violating data hiding (encapsulation)? No. Classes are deciding whom to make friends and give access to.