Friend classes in C++ give us access to non-member functions or other classes. In this article Kais shows us exactly how and why we should use friend classes and functions.
C++ Tricks of the Trade: Friend Functions - Commutative Operators (Page 3 of 5 )
Overloading operator+ allows the rational class to behave more like an intrinsic data type. To add two rational numbers, we can overload the operator as a class member:
const CRational CRational::operator+(const CRational &r) { // add *this to r, and return the result by value. // ... }
The operator+ function can also be overloaded to handle the addition of a rational, and a non-rational type. If n is an integer, and r is a rational then we could implement r + n as a class member:
const CRational CRational::operator+(const int n) { // add *this to n, and return the result by value // ... }
Since operator+ is an example of a commutative operator, we would expect r + n to have the same semantics as n + r. In the second case we need to use a non-member function:
class CRational { friend const CRational operator+(const int n, const CRational &r);
// ... }
This function could be written as a non-friend function, provided that get/set member functions are used. Doing so would turn the function into a plain non-member function, and so it would not be clear how it interacts with the class. By using a friend function, readers of the class declaration see that operator+ forms part of the CRational interface, and is semantically part of the class.
Friends and Virtual Functions A problem with friends is that class member functions can be virtual while non-member functions can’t. The equivalent of a virtual friend function is useful when deriving from a class that has a friend function.
An example of where the equivalent of a virtual friend would be useful is if serializing an entire class hierarchy. The trick in doing this is to turn the friend function into a lightweight inline proxy function, which forwards the request back to the class. For example, consider the simple base class:
class CPerson { friend ostream &operator<< (ostream &out, CPerson &person);
In a class hierarchy using the base CPerson class, each derived class has its own implementation of the display function:
class CBob : public CPerson { protected: virtual ostream &display(ostream &out) { out << "Bob"; return out; } };
This is just as efficient as using a virtual friend function (if such a thing existed) since a good compiler will replace a call to operator<< with a call to the display function, which each derived class implements.