FAQs in section [14]:
[14.1] What is a friend?
Something to allow your class to grant access to another class or function.
Friends can be either functions or other classes. A class grants access
privileges to its friends. Normally a developer has political and technical
control over both the friend and member functions of a class (else you may
need to get permission from the owner of the other pieces when you want to
update your own class).
[ Top | Bottom | Previous section | Next section ]
[14.2] Do friends violate encapsulation?
If they're used properly, they actually enhance encapsulation.
You often need to split a class in half when the two halves will have
different numbers of instances or different lifetimes. In these cases, the two
halves usually need direct access to each other (the two halves used to
be in the same class, so you haven't increased the amount of code
that needs direct access to a data structure; you've simply reshuffled
the code into two classes instead of one). The safest way to implement this
is to make the two halves friends of each other.
If you use friends like just described, you'll keep private things
private. People who don't understand this often make naive efforts to avoid
using friendship in situations like the above, and often they actually destroy
encapsulation. They either use public data (grotesque!), or they make the
data accessible between the halves via public get() and set() member
functions. Having a public get() and set() member function for a
private datum is OK only when the private datum "makes sense" from outside
the class (from a user's perspective). In many cases, these get()/set()
member functions are almost as bad as public data: they hide (only) the
name of the private datum, but they don't hide the existence of the
private datum.
Similarly, if you use friend functions as a syntactic variant of a class's
public: access functions, they don't violate encapsulation any more than a
member function violates encapsulation. In other words, a class's friends
don't violate the encapsulation barrier: along with the class's member
functions, they are the encapsulation barrier.
[ Top | Bottom | Previous section | Next section ]
[14.3] What are some advantages/disadvantages of using
friend functions?
They provide a degree of freedom in the interface design options.
Member functions and friend functions are equally privileged (100% vested).
The major difference is that a friend function is called like f(x),
while a member function is called like x.f(). Thus the ability to
choose between member functions (x.f()) and friend functions
(f(x)) allows a designer to select the syntax that is deemed most
readable, which lowers maintenance costs.
The major disadvantage of friend functions is that they require an extra line
of code when you want dynamic binding. To get the effect of a virtual
friend, the friend function should call a hidden (usually protected:)
virtual member function. This is called the
Virtual Friend Function Idiom. For example:
class Base {
public:
friend void f(Base& b);
// ...
protected:
virtual void do_f();
// ...
};
inline void f(Base& b)
{
b.do_f();
}
class Derived : public Base {
public:
// ...
protected:
virtual void do_f(); // "Override" the behavior of f(Base& b)
// ...
};
void userCode(Base& b)
{
f(b);
}
The statement f(b) in userCode(Base&) will invoke
b.do_f(), which is virtual. This means
that Derived::do_f() will get control if b is actually a object
of class Derived. Note that Derived overrides the behavior of the
protected: virtual member function do_f();
it does not have its own variation of the friend function,
f(Base&).
[ Top | Bottom | Previous section | Next section ]
[14.4] What does it mean that "friendship is
neither inherited nor transitive"?
I may declare you as my friend, but that doesn't mean I necessarily trust
either your kids or your friends.
- I don't necessarily trust the kids of my friends. The privileges of
friendship aren't inherited. Derived classes of a friend aren't necessarily
friends. If class Fred declares that class Base is a friend,
classes derived from Base don't have any automatic special access rights to
Fred objects.
- I don't necessarily trust the friends of my friends. The privileges
of friendship aren't transitive. A friend of a friend isn't necessarily a
friend. If class Fred declares class Wilma as a friend, and class
Wilma declares class Betty as a friend, class Betty doesn't
necessarily have any special access rights to Fred objects.
[ Top | Bottom | Previous section | Next section ]
[14.5] Should my class declare a member function or a
friend function?
Use a member when you can, and a friend when you have to.
Sometimes friends are syntactically better (e.g., in class Fred, friend
functions allow the Fred parameter to be second, while members require it to
be first). Another good use of friend functions are the binary infix
arithmetic operators. E.g., aComplex + aComplex should be defined as a
friend rather than a member if you want to allow aFloat + aComplex as
well (member functions don't allow promotion of the left hand argument, since
that would change the class of the object that is the recipient of the member
function invocation).
In other cases, choose a member function over a friend function.
[ Top | Bottom | Previous section | Next section ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised Jul 10, 2000
|