friend Functions and friend Classes
A friend function of a class is defined outside that class's scope, yet has the right to access the non-public (and public) members of the class. Standalone functions or entire classes may be declared to be friends of another class.
Using friend functions can enhance performance. This section presents a mechanical example of how a friend function works. Later in the book, friend functions are used to overload operators for use with class objects (Chapter 11) and to create iterator classes (Chapter 21). Objects of an iterator class can successively select items or perform an operation on items in a container class object (see Section 10.9). Objects of container classes can store items. Using friends is often appropriate when a member function cannot be used for certain operations, as we will see in Chapter 11.
To declare a function as a friend of a class, precede the function prototype in the class definition with keyword friend. To declare all member functions of class ClassTwo as friends of class ClassOne, place a declaration of the form
friend class ClassTwo;
in the definition of class ClassOne.
Software Engineering Observation 10.7
Even though the prototypes for friend functions appear in the class definition, friends are not member functions. |
Software Engineering Observation 10.8
Member access notions of private, protected and public are not relevant to friend declarations, so friend declarations can be placed anywhere in a class definition. |
Good Programming Practice 10.1
Place all friendship declarations first inside the class definition's body and do not precede them with any access specifier. |
Friendship is granted, not takeni.e., for class B to be a friend of class A, class A must explicitly declare that class B is its friend. Also, the friendship relation is neither symmetric nor transitive; i.e., if class A is a friend of class B, and class B is a friend of class C, you cannot infer that class B is a friend of class A (again, friendship is not symmetric), that class C is a friend of class B (also because friendship is not symmetric), or that class A is a friend of class C (friendship is not transitive).
Software Engineering Observation 10.9
Some people in the OOP community feel that "friendship" corrupts information hiding and weakens the value of the object-oriented design approach. In this text, we identify several examples of the responsible use of friendship. |
Modifying a Class's private Data With a Friend Function
Figure 10.15 is a mechanical example in which we define friend function setX to set the private data member x of class Count. Note that the friend declaration (line 10) appears first (by convention) in the class definition, even before public member functions are declared. Again, this friend declaration can appear anywhere in the class.
Figure 10.15. Friends can access private members of a class.
(This item is displayed on pages 542 - 543 in the print version)
1 // Fig. 10.15: fig10_15.cpp 2 // Friends can access private members of a class. 3 #include 4 using std::cout; 5 using std::endl; 6 7 // Count class definition 8 class Count 9 { 10 friend void setX( Count &, int ); // friend declaration 11 public: 12 // constructor 13 Count() 14 : x( 0 ) // initialize x to 0 15 { 16 // empty body 17 } // end constructor Count 18 19 // output x 20 void print() const 21 { 22 cout << x << endl; 23 } // end function print 24 private: 25 int x; // data member 26 }; // end class Count 27 28 // function setX can modify private data of Count 29 // because setX is declared as a friend of Count (line 10) 30 void setX( Count &c, int val ) 31 { 32 c.x = val; // allowed because setX is a friend of Count 33 } // end function setX 34 35 int main() 36 { 37 Count counter; // create Count object 38 39 cout << "counter.x after instantiation: "; 40 counter.print(); 41 42 setX( counter, 8 ); // set x using a friend function 43 cout << "counter.x after call to setX friend function: "; 44 counter.print(); 45 return 0; 46 } // end main
|
Function setX (lines 3033) is a C-style, stand-alone functionit is not a member function of class Count. For this reason, when setX is invoked for object counter, line 42 passes counter as an argument to setX rather than using a handle (such as the name of the object) to call the function, as in
counter.setX( 8 );
As we mentioned, Fig. 10.15 is a mechanical example of using the friend construct. It would normally be appropriate to define function setX as a member function of class Count. It would also normally be appropriate to separate the program of Fig. 10.15 into three files:
- A header file (e.g., Count.h) containing the Count class definition, which in turn contains the prototype of friend function setX
- An implementation file (e.g., Count.cpp) containing the definitions of class Count's member functions and the definition of friend function setX
- A test program (e.g., fig10_15.cpp) with main
Erroneously Attempting to Modify a private Member with a Non-friend Function
The program of Fig. 10.16 demonstrates the error messages produced by the compiler when non-friend function cannotSetX (lines 2932) is called to modify private data member x.
Figure 10.16. Non-friend/nonmember functions cannot access private members.
(This item is displayed on pages 544 - 545 in the print version)
1 // Fig. 10.16: fig10_16.cpp 2 // Non-friend/non-member functions cannot access private data of a class. 3 #include 4 using std::cout; 5 using std::endl; 6 7 // Count class definition (note that there is no friendship declaration) 8 class Count 9 { 10 public: 11 // constructor 12 Count() 13 : x( 0 ) // initialize x to 0 14 { 15 // empty body 16 } // end constructor Count 17 18 // output x 19 void print() const 20 { 21 cout << x << endl; 22 } // end function print 23 private: 24 int x; // data member 25 }; // end class Count 26 27 // function cannotSetX tries to modify private data of Count, 28 // but cannot because the function is not a friend of Count 29 void cannotSetX( Count &c, int val ) 30 { 31 c.x = val; // ERROR: cannot access private member in Count 32 } // end function cannotSetX 33 34 int main() 35 { 36 Count counter; // create Count object 37 38 cannotSetX( counter, 3 ); // cannotSetX is not a friend 39 return 0; 40 } // end main Borland C++ command-line compiler error message:
Microsoft Visual C++.NET compiler error messages:
GNU C++ compiler error messages:
|
It is possible to specify overloaded functions as friends of a class. Each overloaded function intended to be a friend must be explicitly declared in the class definition as a friend of the class.