How Does the Friend Keyword (Class/Function) Break Encapsulation in C++

When should you use 'friend' in C++?

Firstly (IMO) don't listen to people who say friend is not useful. It IS useful. In many situations you will have objects with data or functionality that are not intended to be publicly available. This is particularly true of large codebases with many authors who may only be superficially familiar with different areas.

There ARE alternatives to the friend specifier, but often they are cumbersome (cpp-level concrete classes/masked typedefs) or not foolproof (comments or function name conventions).

Onto the answer;

The friend specifier allows the designated class access to protected data or functionality within the class making the friend statement. For example in the below code anyone may ask a child for their name, but only the mother and the child may change the name.

You can take this simple example further by considering a more complex class such as a Window. Quite likely a Window will have many function/data elements that should not be publicly accessible, but ARE needed by a related class such as a WindowManager.

class Child
{
//Mother class members can access the private parts of class Child.
friend class Mother;

public:

string name( void );

protected:

void setName( string newName );
};

C++ Friend Functions Improve Encapsulation?

I'd say that a friend function is simply an extension of the public interface of the class, which uses a slightly different syntax and allows implicit conversions on all of its parameters (whereas member functions don't do that on their first/implied parameter).

In other words, the author of the class which grants friendship should be the one in control of the friend function. If you just declare a friend function in your class and allow clients to define that function, then certainly hell breaks loose (and program breaks down). But that's not what friend functions are for.

C++ friend functions/class uses?

"In C++, only your friends can access your private parts."

The point of a friend is that you can package your software into smaller groupings, like friend classes etc, while still allowing access to the internals of a class. This arguably lets you maintain finer control on encapsulation than without friending.

Why does C# not provide the C++ style 'friend' keyword?

Having friends in programming is more-or-less considered "dirty" and easy to abuse. It breaks the relationships between classes and undermines some fundamental attributes of an OO language.

That being said, it is a nice feature and I've used it plenty of times myself in C++; and would like to use it in C# too. But I bet because of C#'s "pure" OOness (compared to C++'s pseudo OOness) MS decided that because Java has no friend keyword C# shouldn't either (just kidding ;))

On a serious note: internal is not as good as friend but it does get the job done. Remember that it is rare that you will be distributing your code to 3rd party developers not through a DLL; so as long as you and your team know about the internal classes and their use you should be fine.

EDIT Let me clarify how the friend keyword undermines OOP.

Private and protected variables and methods are perhaps one of the most important part of OOP. The idea that objects can hold data or logic that only they can use allows you to write your implementation of functionality independent of your environment - and that your environment cannot alter state information that it is not suited to handle. By using friend you are coupling two classes' implementations together - which is much worse then if you just coupled their interface.

When to use friend class in C++

I agree with the comments that say the friend keyword can improve encapsulation if used wisely. I'd just add that the most common (legitimate!) use for friend classes may be testing. You may want a tester class to have a greater degree of access than other client classes would have. A tester class could have a good reason to look at internal details that are deliberately hidden from other classes.

When should you use friend classes?

Friend is used for granting selective access, just like the protected access specifier. It's also hard to come up with proper use case where use of protected is really useful.

In general, friend classes are useful in designs where there is intentional strong coupling: you need to have a special relationship between two classes. More specifically, one class needs access to another classes's internals and you don't want to grant access to everyone by using the public access specifier.

The rule of thumb: If public is too weak and private is too strong, you need some form of selected access: either protected or friend (the package access specifier in Java serves the same kind of role).

Example design

For instance, I once wrote a simple stopwatch class where I wanted to have the native stopwatch resolution to be hidden, yet to let the user query the elapsed time with a single method and the units to be specified as some sort of variable (to be selected by user preferences, say). Rather than, have say elapsedTimeInSeconds(), elapsedTimeInMinutes(), etc. methods, I wanted to have something like elapsedTime(Unit::seconds). To achive both of these goals, I can't make the native resolution public nor private, so I came up with the following design.

Implementation overview

class StopWatch;

// Enumeration-style class. Copy constructor and assignment operator lets
// client grab copies of the prototype instances returned by static methods.
class Unit
{
friend class StopWatch;
double myFactor;
Unit ( double factor ) : myFactor(factor) {}
static const Unit native () { return Unit(1.0); }
public:
// native resolution happens to be 1 millisecond for this implementation.
static const Unit millisecond () { return native(); }

// compute everything else mostly independently of the native resolution.
static const Unit second () { return Unit(1000.0 / millisecond().myFactor); }
static const Unit minute () { return Unit(60.0 / second().myFactor); }
};

class StopWatch
{
NativeTimeType myStart;
// compute delta using `NativeNow()` and cast to
// double representing multiple of native units.
double elapsed () const;
public:
StopWatch () : myStart(NativeNow()) {}
void reset () { myStart = NativeNow(); }
double elapsed ( const Unit& unit ) const { return elapsed()*unit.myFactor; }
};

As you can see, this design achieves both goals:

  1. native resolution is never exposed
  2. desired time unit can be stored, etc.

Discussion

I really like this design because the original implementation stored the multiple of native time units and performed a division to compute the elapsed time. After someone complained the division was too slow, I changed the Unit class to cache the dividend, making the elapsed() method (a little) faster.

In general, you should strive for strong cohesion and weak coupling. This is why friend is so little used, it is recommended to reduce coupling between classes. However, there are situations where strong coupling gives better encapsulation. In those cases, you probably need a friend.

In what scenarios should one declare a member function a friend?

You would use a friend function for the same sort of reasons that you would use a friend class, but on a member function (rather than entire class) basis. Some good explanations are in this thread.

While friend functions and classes do violate encapsulation, they can be useful in some scenarios. For example, you may want to allow a test harness to access class internals to allow you to do whitebox testing. Rather than opening up the entire class to the test harness, you could open up a particular function which accesses the internals required by the test harness. While this still violates encapsulation, it's less risky than opening up the entire class.

Also see this article for some more information about friend classes and functions.

restriction on friend function

a derived class doesn't inherit friend functions? […] why?

Because that would break encapsulation: the derived class couldn’t control its friends any longer so it effectively cannot control who has access to its internals.

they may not be declared as static or extern, why?

Because static would make no sense (it only makes sense in functions belonging to a class, and friends are free functions), and extern would once again violate encapsulation because the class effectively cannot control any longer which function has access to it: due to being extern, the friend could effectively come from a different compilation unit, unknown to the class.

See Jan’s answer for a correction.



Related Topics



Leave a reply



Submit