[Postscript]

Friends

A friend is allowed access the private data of a class. The friend modifier can be applied to both functions and classes. Both uses are for similar purposes: Functions are frequently defined as friends of a class so that they can access and change the data in the private area of a class; Classes are declared friends of a other class so that they can access and change the private data of the other class.

Friend Classes

When class A is made a friend of class B, it implies that the member functions of class A have access to the private data of class B.
singlespace12

This feature is occasionally useful and should be utilized on a very limited basis. Its general use is discouraged for it puts the private data items of class B in the public interface of a second class, violating the principles of information hiding and encapsulation. It is much better to develop access functions to interrogate the data of class B and member functions of B that allow the functions of A to modify the data of B. Also, if class A is so intrinsically linked to class B so that it must access its member functions, then the designer should consider the possibility of deriving class A from B.

Its primary use is in the construction of linked lists, where the pointers are kept with the data.
singlespace25

In this case, the DataList class is the one that manages the next_item pointer in the DataItem class.

This is a technique that is frequently utilized by novice programmers when they want one class be able to change the data of a second class - without going through the process to produce a well-designed class with proper member functions and data access functions. The pitfall that they usually encounter is that only the member functions of class A can access the private data of B, not the friend functions. To find a workaround to this, they frequently opt for the easy out which is to put the private data of B into the public interface - which violates the principles of encapsulation and information hiding.

Making one class a friend of another is a bad practice in general and should be avoided.

Friend Functions

The writer of C++ programs always has a problem as to whether to make a function a member function or a friend function. In general, this appears to be a complex question, but actually has a straightforward answer.

First, any function that is to be made virtual must be a class member. Second, Functions are made friend functions when the function must have access to the private data of a class, and when either

The reasons for these conditions are examined below. However, so as not to have to evaluate each function on a case-by-case basis, we state the following rule : All binary and multiple parameter operators should be defined as friend functions instead of member functions. This is not absolute, nor does it guarantee that a function must be declared a friend to function properly, but it works in virtually all cases. Those exceptional cases must be examined on an individual basis.

Example 1 - operator<< - order independent

In the case of operator<< the routine is defined in the interface by

      friend ostream& operator<< ( ostream&, const Vector& ) ;
If it were defined as a member function it would have been defined as
      ostream& operator<< ( ostream& ) ;
which would imply that it is called in the following way by the calling routine
singlespace42
which is equivalent to
singlespace44

which is backwards, as to the way that the << operator is used. We could define it as a global function outside of the class interface, but in order to print the contents of the class it needs access to the private data. Thus, it must be defined as a friend function.

      friend ostream& operator<< ( ostream&, const Vector& ) ;

Binary Operators

In the case of binary operators like ==, !=, +, or -, the problem is in the first parameter. If we take operator* (scalar multiplication for Vectors) as an example, and define it as a member function, it would appear as
singlespace54

This works very well for expressions of the form
singlespace56
But this does not work for expressions of the form

      v1 = c * v2 ;    // or v1 = c.operator* ( v2 ) ;
as the double type does not have an operator* that takes Vectors as parameters.

It is necessary to have both examples above compile and execute, as we want scalar multiplication to be commutative. The definition of two scalar multiplication functions as friends solves the problem
singlespace60
Each of the above cases will now compile and execute correctly.

Type Conversion

An example of the conversion problem is best illustrated with strings.

Consider a string class String, and the concatenation operator+ that concatenates two Strings into one. This operator could be defined as a member function by

      String operator+ ( const String& ) ;
and could be called by
singlespace66
It is clear that this works in either order - but we are not yet off the hook because in most string classes there is a constructor
      String ( const char * ) ;
that converts character strings to Strings. In this case, the C++ compiler will perform type conversion automatically and the concatenation can take the form
singlespace69

The second form cannot execute, as a member function is only invoked if the left operand is an explicit class object.

Thus, if we desire automatically type conversion (and we usually do because it is a powerful feature), then defining this concatenation as a member function does not work in all cases. However, defining the concatenation operator as a friend function

      friend String operator+ ( const String&, const String& ) ;
will work in all cases, as type conversion can be done to each of the parameters of such a function.

Thus, the general rule : Define all binary operators as friend functions. It will work.

This document maintained by Ken Joy.
Comments to the author : joy@cs.ucdavis.edu

All contents copyright (c) 1998
Computer Science Department, University of California, Davis
All rights reserved.



Ken Joy
Wed Jan 7 14:56:41 PST 1998