The friend
keyword in C++ is one of those concepts that is formally taught, but then seems to disappear off the scene once you get into the real world. Maybe friends are less common in embedded programming (ha ha), but I’ve seen very few of them over the years.
The thing is, they just don’t seem to be at the forefront of people’s minds when writing code. When would you ever actually use one of these things?
Aren’t they just a way to avoid writing getters and setters??
I think when you are learning a language, understanding concrete examples of why a concept is there is absolutely necessary if that concept is to stick and be used well.
So let’s have a look at friend
functions and classes and see what on earth we could do with them.
The Official Explanation – Example 1
Declaring a function (or class) as a friend means that the function (or class) can access the private area of that class’ declaration.
In all other ways, nothing else is different. The friendship is one way, limited only to the class in which you add it, and has no other effect on either class/method involved (including sub classes, base classes and other friend classes). It defines a single relationship.
So, we can assign any old class, or function, in our code base, to be a friend of another class, by adding it to the declaration of that other class with the friend
keyword. Let’s see that in code, so we are certain we know what’s going on.
Here’s our class:
class Rectangle
{
public:
friend class Puzzle;
friend float CalculateArea();
private:
};
class Puzzle
{
};
float CalculateArea()
{
}
OK, so this is a contrived example (as they always are), but bear with me. We’ll get to changing that in a minute.
For now, let’s just look at the way we use the keyword.
We’ve got an ordinary class (Puzzle
), and an ordinary function (CalculateArea
), and both have been added to the Rectangle
class declaration as friends.
Now Puzzle
and CalculateArea
can access Rectangle
’s private
data and private
methods.
That’s all there is to it.
But Why Would You Ever Want To Do This?
We all know that C++ is a powerful language that allows you to model the real world in terms of objects, and interactions between those objects.
Encapsulation is one of the big concepts in C++, a cornerstone of the language. It means that classes contain their own data, and methods to manipulate that data, independently of the other parts of the program.
So, on the surface, it may seem as if adding friend
classes and functions goes against this idea: if you add friend
s to a class, they aren’t independently managing their own data anymore. Things could get messy!!
Not quite.
The thing is, in the real world, objects aren’t completely discrete items. Take even the contrived example above – a Puzzle
class might be a friend of a Rectangle
, a Square
and a Polygon
because it needs to calculate how to fit them into a predefined area.
You can’t use inheritance (a rectangle
is a kind of puzzle
? Nope), and templates are no good either.
Just imagine that collection of objects – rectangles, squares and crosses – all jiggling around trying to calculate their own position on the board. It wouldn’t work! A puzzle
class however, can fit them together. But the Puzzle
class needs to know all sorts of things about the objects it is positioning.
Instead of having to add identical calling methods for number of sides, side length, etc. to each shape, if you make the Puzzle
class a friend of each shape, it can access the private
data that it needs and does the job neatly. It simplifies all the shape objects and keeps the puzzle workings in a separate class. Much better.
Actually, I said that was a contrived example, but it’s not too bad, is it?
Example 2
class Message
{
public:
friend class MessageStats;
private:
};
In this case, we’ve got a Message
class with a friend
class called MessageStats
.
Let’s assume the Message
class itself doesn’t always deliver a complete message. Maybe the transmission packet only has room for a certain number of bytes, and messages have to be reconstructed on arrival out of several Message
objects.
By giving MessageStats
direct access to the private
data of Message
, it can keep a tally of how many whole messages are received in a day, even though some of the objects it looks at will be individual parts of a single message.
MessageStats
could also keep a tally of error messages received, or any other kind of message that you wanted to keep an eye on.
Again, instead of having to write methods to return all of this information to a non-friend class (because you would never make the private
data public
, right?), the MessageStats
class can access it directly.
To the “public
” (i.e. the rest of your code), there is the choice of interacting with Message
or MessageStats
, but the raw data is held in one place and untouchable by everything else.
Friends can simplify and reduce the amount of code that you need to write.
Example 3
Let’s look at one more before we finish up.
Friend
classes are really handy if you have to delve into operator overloading. This is when you redefine how (for example) the multiplication operator works so that you can use it on your own objects.
Not clear?
Okay, imagine that you have two different classes that contain numeric data. One may store integers as an array, the other as a two dimensional array. You want to be able to multiply the data together (like matrix multiplication, if you are familiar with it).
If you create an overloaded “*” method, and include it as a friend of the two classes that you want to multiply together, the overloaded “*” method can access the private
numerical data of each object, and you can write:
multiplied_object = object1 * object2;
The same goes for any operator that you want to tailor to your specific needs.
Say you want to print an object to stdout
:
cout << yourobject << endl;
Create an overloaded <<
method, and then add it as a friend
to your class – the new <<
method can access the private
data directly to print it to your screen.
What About Encapsulation?
As I said above, it might seem at first as though friends are entangling things, but that’s not the case. The C++ FAQ puts it beautifully in saying:
Try thinking of a friend function as part of the class’s public interface.
And this is exactly what you should do.
Visually, it might look a little like this:
|= Lots of other classes and code in the rest of your program =| <- other code
|____Class____| |____Friend Class____| |____Friend function____| <- interface
|--- data ----| <- private data
In a nutshell:
A friend is a way to contain similar methods and ideas that are outside the scope of the original class, but that are intrinsically reliant on that class’ data.