Lesson 5 | Why friend functions are needed |
Objective | Write two add() functions for the matrix class |
Why friend Functions are needed in C++
Write two add() functions to the matrix class
- one a friend function and
- the other a member function
and explain the advantages of defining one over the other.
The keyword
friend
is a function specifier and gives a
non-member function access to the hidden members of the class, and provides a method of escaping the data hiding restrictions of C++.
However, you must have a good reason for escaping these restrictions, as they are both important to reliable programming.
There are two reasons why you might use a friend function:
Some functions need privileged access to more than one class. For example, we want to write a function that multiplies a
matrix by a vector.
Privileged Access to more than One Class
A function multiplying a vector by a matrix, as represented by these two classes, could be written efficiently if it had access to the private
members of both classes. It would be a friend
function of both classes.
class matrix; //forward reference
class vect {
public:
friend vect mpy(const vect& v, const matrix& m);
.....
private:
int* p;
int size;
};
class matrix {
public:
friend vect mpy(const vect& v, const matrix& m);
.....
private:
int** p;
int s1, s2;
};
vect mpy(const vect& v, const matrix& m){
assert(v.size == m.s1); //check sizes
//use privileged access to p in both classes
vect ans(m.s2);
int i, j;
for (i = 0; i <= m.s2; ++i) {
ans.p[i] = 0;
for (j = 0; j <= m.s1(); ++j)
ans.p[i] += v.p[j] * m.p[j][i];
}
return ans;
}
A minor point is that a forward declaration of the class matrix
is necessary.
This is because the function mpy()
must appear in both classes, and it uses each class as an argument type.
All friend
functions pass all their arguments through the argument list, and each argument value is subject to assignment-compatible conversions. Here is an example of this situation. Conversions would apply to an object passed explicitly and would be especially useful in cases of binary operator overloading, as we will see a bit later in this module.
Passing Arguments through the argument list
All friend
functions pass all their arguments through the argument list, and each argument value is subject to assignment-compatible conversions. Here is an example:
class pandaBear {
...
pandaBear (int);
int memberFunction();
friend int nonMemberFunction(const pandaBear&);
}
class designPattern {
...
designPattern (int);
int memberFunction();
friend int nonMemberFunction(const designPattern&);
}
When a member function is invoked, no user-defined conversions are applied.
On the other hand, this conversion will be applied to the argument of friendFunction()
in the following call:
nonMemberFunction (5);
Therefore if an implicit function argument type conversion is desired in an operation,
the function implementing this operation must be a nonmember function.
Friends
Friends of classes are granted access to all members of the class. You can declare functions (including member functions
of other classes) or entire classes as friends of a class. For example:
class Account
{
friend class AccountManager;
friend void doDefaultDebit(Account &a);
friend void ATM::deductFee(Account &a, double fee);
public:
Account(double b);
void deposit(double amt);
void withdraw(double amt);
void getBalance( ) const;
private:
double balance;
};
The following rules apply to friends:
- Declarations of friends can appear anywhere within a class definition, but usually appear at the beginning.
- The access specifier under which friends appear makes no difference.
- Friendship is not inherited, nor do friends of nested classes have any special access rights to the members of their enclosing class.
- Functions first declared as friends have external linkage; otherwise, they retain their linkage.
Friends must be explicitly declared as part of Class Definition
The modifiers
- private,
- protected, and
- public
give the programmer control over access to names, which implicitly gives the programmer control over access to their associated data values. However, the three possibilities of public, protected, and private cannot cover all situations. Frequently a programmer would like to make a data field or member function accessible to another function or another class that is not a derived class, and to do so without making the name accessible in a public fashion. The solution in this case is to declare a friend. A friend can be either another class or a function. The friend must be explicitly named within a class definition. By naming the friend, the class is granting access to all the private features of the class. Declaring a class as friend means that all member functions in the friend class are friends. Needless to say, this is a dangerous mechanism because it exposes the encapsulated state of a class to outside modification. Friendship is not something that should be given away freely. But because friends are named, and because friends are allowed direct access to internal data fields, friendship is a more precise and efficient mechanism than, for example, the creation of
accessor functions[1] .
class ClassName{
...
friend class ClassName;
friend return_type function_name(parameter list);
};
Friend Function - Exercise
Click the Exercise link below to write two
add()
functions to the
matrix class
.
- one a
friend
function and
- the other a member function
and explain the advantages of defining one over the other.
Friend Function - Exercise
[1]accessor functions: Member functions that are public are called accessor functions when they do not change the object's data.