PART 6 Q24: What is a `friend'? A: Friends can be either functions or other classes. The class grants friends unlimited access privileges. Q25: Do `friends' violate encapsulation? A: Friends can be looked at three ways: (1) they are not class members and they therefore violate encapsulation of the class members by their mere existence, (2) a class' friends are absorbed into that class' encapsulation barrier, and (3) any time anyone wants to do anything tricky they textedit the header file and add a new friend so they can get right in there and fiddle 'dem bits. No one argues that (3) is a Good Thing, and for good reasons. The arguments for (1) always boil down to the rather arbitrary and somewhat naive view that a class' member functions `should' be the *only* functions inside a class' encapsulation barrier. I have not seen this view bear fruit by enhancing software quality. On the other hand, I have seen (2) bear fruit by lowering the *overall* coupling in a software system. Reason: friends can be used as `liaisons' to provide safe, screened access for the whole world, perhaps in a way that the class syntactically or semantically isn't able to do for itself. Conclusion: friend functions are merely a syntactic variant of a class' public access functions. When used in this manner, they don't violate encapsulation any more than a member function violates encapsulation. Thus a class' friends and members *are* the encapsulation barrier, as defined by the class itself. I've actually seen the `friends always violate encapsulation' view *destroy* encapsulation: programmers who have been taught that friends are inherently evil want to avoid them, but they have another class or fn that needs access to some internal detail in the class, so they provide a member fn which exposes the class' internal details to the PUBLIC! Private decisions should stay private, and only those inside your encapsulation barrier (your members, friends, and [for `protected' things] your subclasses) should have access. Q26: What are some advantages/disadvantages of using friends? A: The advantage of using friends is generally syntactic. Ie: both a member fn and a friend are equally privileged (100% vested), but a friend function can be called like f(obj), where a member is called like obj.f(). When it's not for syntactic reasons (which is not a `bad' reason -- making an abstraction's syntax more readable lowers maintenance costs!), friends are used when two or more classes are designed to be more tightly coupled than you want for `joe public' (ex: you want to allow class `ListIter' to have more privilege with class `List' than you want to give to `main()'). Friends have three disadvantages. The first disadvantage is that they add to the global namespace. In contrast, the namespace of member functions is buried within the class, reducing the chance for namespace collisions for functions. The second disadvantage is that they aren't inherited. That is, the `friendship privilege' isn't inherited. This is actually an advantage when it comes to encapsulation. Ex: I may declare you as my friend, but that doesn't mean I trust your kids. The third disadvantage is that they don't bind dynamically. Ie: they don't respond to polymorphism. There are no virtual friends; if you need one, have a friend call a hidden (usually `protected:') virtual member fn. Friends that take a ptr/ref to a class can also take a ptr/ref to a publically derived class object, so they act as if they are inherited, but the friendship *rights* are not inherited (the friend of a base has no special access to a class derived from that base). Q27: What does it mean that `friendship is neither inherited nor transitive'? A: This is speaking of the access privileges granted when a class declares a friend. The access privilege of friendship is not inherited: * I may trust you, but I don't necessarily trust your kids. * My friends aren't necessarily friends of my kids. * Class `Base' declares f() to be a friend, but f() has no special access rights with class `Derived'. The access privilege of friendship is not transitive: * I may trust you, and you may trust Sam, but that doesn't necessarily mean that I trust Sam. * A friend of a friend is not necessarily a friend. Q28: When would I use a member function as opposed to a friend function? A: Use a member when you can, and a friend when you have to. Like in real life, my family members have certain privileges that my friends do not have (ex: my family members inherit from me, but my friends do not, etc). To grant privileged access to a function, you need either a friend or a member; there is no additional loss of encapsulation one way or the other. Sometimes friends are syntactically better (ex: in class `X', friend fns allow the `X' param to be second, while members require it to be first). Another good use of friend functions are the binary infix arithmetic operators. Ex: `aComplex + aComplex' probably should be defined as a friend rather than a member, since you want to allow `aFloat + aComplex' as well (members don't allow promotion of the left hand arg, since that would change the class of the object that is the recipient of the message).