|
|
Summary
6) Friend functions
7) Declaration of Friend Functions
8) Sample Program 1
9) Sample Program 2
10) Sample Program 3
11) Friend Classes
12) Summary
Friend functions
Today, we are going to discuss a very interesting subject i.e. Friend Functions.
We will
see what is the relationship of friendship with our object-based programming. Before
going into details of the subject, it is better to have a fresh look on the definition
of
‘class’. ‘Class is a user defined data type’. The ‘class’ provides encapsulation
facility to
the programmer. We can gather data at some place and some function that manipulates
that data. In the previous lecture, two keywords, ‘private’ and ‘public’ were introduced.
We define data members as ‘private’ that are visible only from inside the class
and
hidden from the outside. However, ‘public data member functions’ is the interface
of the
class available for outside world. Objects are accessed by these functions that
can
manipulate the private data of the class. We cannot access the private data of the
class
directly. This concept of data encapsulation and data hiding is very important concept
in
software engineering. It allows us to separate the interface from the implementation
of
the class i.e. we can hide how we have done the task and make visible what to do.
It is
critically important for large and complex systems. Sometimes, a need may arise
to
access the private data of the class from outside.
Let’s talk about the concept of friendship. What you see on the screen during the
lecture
is the picture of the instructor. This is the public interface. That is all you
know. What is
Page 364
inside his mind you never know. It is all ‘private’. The instructor has access to
his own
mind and feelings. But you do not have access to that. Do you know any human being
who has access to your mind and feelings? What we call that human being. He is known
as friend. Normally other people don’t know about our thoughts. Only friends know
about it. Friends have access to the inner thoughts and have inner knowledge of
a friend.
Can we apply this definition to objects?
The friend functions of a class have access to the private data members of class.
Despite
being a good thing, there is possibility of vulnerability. We are opening our thoughts,
inside view for somebody else. Without having 100% trust, it will be risky to make
our
thoughts and feelings public. We want that our private data is accessible to someone
outside, not public for everybody. Otherwise, the data encapsulation and data-hiding
concept will be violated. We keep the data members private and declare some specific
functions that are not member of the class but friend of the class. As friends,
they have
access to the inside data structure of the class despite not being members.
Declaration of Friend functions
To declare a friend function, we can put it anywhere in the class. According to
the
definition of the friend functions, they have access to the private data members
of the
class. These can also access the private utility functions of the class. The question
arises
where we should put the friend function whether in the private or public part of
the class.
Be sure that friend is a very strong statement. It is too strong to be affected
by public or
private. We can put it anywhere in the class. But remember that friend functions
are not
member of the class. So their definition will be always outside the class. However,
the
prototype of the function will be written in the class. We use the keyword ‘friend’
before
the prototype of the function.
friend return_type friend_function_name(int, char);
If we have a class, suppose ‘Date’ and want to declare a friend function of this
class. In
the definition of the class, we will write the friend function’s prototype with
the keyword
‘friend’. To access the private data, friend function will need the object. Therefore,
usually in the parameter list of friend function, we provide the object of that
class.
Normally, the programmers work this way. As the friend function is not affected
by the
private or public keyword, so we can declare it anywhere inside the class definition.
Programmers generally declare the friend functions at the top of the class definition.
So,
the friend functions are declared at the start of the class definition, followed
by the
private data and public data. This is a guideline. You can develop your own style.
We
normally make a header file of the class definition and implementation in the other
file.
The member functions are defined in the implementation file and compiled to get
an
object file. We declare the friend function in the class definition that is in the
header file.
Let’s go back to the definition of the friendship. I can declare you my friend and
tell you
about my inner thoughts and feelings. But it does not work both ways. In other words,
friendship is granted, never taken. So, a class can declare a friend function and
someone
from outside the class cannot declare itself friend of a class. This is also an
important
Page 365
concept. If someone from outside the class can declare itself friend of the class,
then by
definition that external function would have access to the private data member of
the
class. But this will negate the concept of the encapsulation and data hiding. It
does not
work this way. A function cannot declare itself friend of a class. Rather, a class
has to
declare itself that a function is friend of the class or not. So the class declares
a friend
function. These functions can not declare themselves friend of a class from outside.
Once,
the friend functions are declared and the class is compiled, no one from outside
cannot
make his function friend of your class. Outside functions can only view the interface
of
the class.
Let’s summaries this concept. Friend functions are not member functions of the class.
The class itself declares the friend functions. The prototype of friend functions
is written
in the definition of the class with the keyword ‘friend’. These functions have access
to the
private data member of the class, which means they have access to everything in
the
class. Normally we pass an object of the class to these functions in the argument
list so
that it can manipulate the data of the object. Style is up to you but normally we
write
friend functions at the top of the class definition.
Sample Program 1
We have a class with a single private data member of type
int. We have declared a
friend
function that accepts an object of that class as argument. We call that friend function
increment. This friend function will increment the private integer data
member of the
class. We will give another integer argument to that function that will be added
to the
data member. The name of the private data member is, for example,
topSecret. Let’s call
the class as myClass.
In the interface, we write
display() function that will print the value
of the topSecret.
The constructor of the class will initialize the
topSecret with 100. The
definition of the friend function will be outside the class. We do not write the
keyword
‘friend’ with the function definition. It will be a void function, having two arguments
as:
void increment(myClass *a, int i)
{
a->topSecret += i;
}
Now the increment function has added the value of
i to the private data member
i.e.
topSecret of the passed object. In the main function, we declare an object
of type myClass
as myClass x; On
the execution of this statement, an object will be created in the
memory. A copy of its data members and functions will also be created besides calling
a
constructor. The place for
topSecret will be reserved in the memory while the constructor
will assign the value 100 to the variable
topSecret. Now if we say
x.display(); it
will
display the value of the topSecret
i.e.100. After this, we call the increment friend function
and pass it &x and
10 as arguments. Again we call the display function of
myClass as
x.display(); Now the value of the
topSecret will be 110.
That means the ‘topSecret’
which
was the private data member of the class has been changed by the
increment friend
function. Be sure that the increment function is not the member function of the
class. It is
an ordinary function sitting outside the class but class itself has declared it
as friend. So
Page 366
now the friend function has access to the private data member and has the ability
to
change it. Try to write an ordinary function (not friend function) ‘increment2’
which tries
to manipulate the topSecret.
See what will happen? The compiler will give an error that a
non- member function can not access the private data of the class.
Here is the complete code of the program.
/*
A sample program showing the use of friend function,
which access the private data member of the class.
*/
#include <iostream.h>
class myClass
{
friend void increment(myClass *, int);
private:
int topSecret;
public:
void display() { cout << "\n The value of the topSecret is " <<
topSecret; }
myClass();
};
// constructor of the class
myClass::myClass()
{
topSecret = 100;
}
// Friend function definition
void increment(myClass *a, int i)
{
a->topSecret += i; // Modify private data
}
// showing the use of the friend function
void main()
{
myClass x;
x.display();
increment(&x, 10);
x.display();
}
Page 367
The output of the program is:
The value of the topSecret is 100
The value of the topSecret is 110
Sample Program 2
Let’s consider some complex example. We have two classes-myClass1
and myClass2.
Both classes have one private data member of type
int i.e.
int topSecret; Now we want
to
add the values of private data members of both the classes and display it on the
screen.
topSecret is a private data member of both the classes. One class can
not see inside the
other class. myClass1
and myClass2
are both separate classes. We need a function sitting
outside the classes but can access the private data members of both the classes.
Let’s call
the function as addBoth.
This function will add the value of
topSecret of
myClass1 to
topSecret of myClass2
and display the result on the screen. We need a function that can
look inside both classes i.e. friend of both classes. We know that classes have
to declare a
function as friend.
The arguments of addBoth
function will contain
myClass1 and
myClass2. In the
definition of the myClass1,
we will write the prototype of
addBoth function as:
friend void addBoth(myClass1, myClass2);
Can we write this line in the definition of the
myClass1? We know that
if we refer some
function as f(x)
and the function f()
is not defined or declared before this, the compiler
will give an error that function
f() is not defined. So
we at least declare the function
before main() so
that compiler successfully compile the program. So there was
declaration of the function before its being called. Now same problem is in our
friend
function prototype. We are referring both classes in it and our program does not
know
anything about myClass2.
We can tackle this problem by writing a line before the
definition of the class myClass1
as:
class myClass2;
It will declare that myClass2
is a class having its definition somewhere else. It is the same
as we declare functions before
main. After writing that
statement, we can refer myClass2
in our code. The definition of the class
myClass1 will be as:
class myClass1
{
private:
int topSecret;
public:
void display() { cout << "\nThe value of the topSecret is " <<
topSecret; }
myClass1();
Page 368
friend void addBoth(myClass1, myClass2);
};
myClass1::myClass1()
{
topSecret = 100;
}
The definition of myClass2
is also similar to
myClass1.
class myClass2
{
private:
int topSecret;
public:
void display() { cout << "\nThe value of the topSecret is " <<
topSecret; }
myClass2();
friend void addBoth(myClass1, myClass2);
};
myClass2::myClass2()
{
topSecret = 200;
}
You must have noted that we have used the
topSecret data member in
both the classes. Is
it legal? Yes it is. There is no problem as one
topSecret is part of
myClass1 and other
is
part of myClass2.
Will there be same problem while declaring the friend function in
myClass2, i.e. myClass1
is not known? No. We have already defined the
myClass1. We
have to declare a class only at a time when we are referring to it and it is not
defined yet.
In the main program, we will take the object of
myClass1 i.e.
myClass1 a; The object
will
be created in the memory and constructor is called to initialize the data members.
The
value of topSecret
will be 100. In the next line, we will take the object of
myClass2 as
myClass2 b; Now
b is an object of class
myClass2. The memory will
be reserved for it. It
has its own data members and the value of
topSecret will be 200,
initialized by the
constructor. Now we will display the values of both data members, using
display()
function.
Now we will call the addBoth(a,
b); As this function is friend of both classes, so it has
access to both the classes and their private data members. The definition of
addBoth
function will be as under:
Page 369
void addBoth(myClass1 a, myClass2 b)
{
cout << “\nThe value of topSecret in the myClass1 object is ” <<
a.topSecret;
cout << “\nThe value of topSecret in the myClass2 object is ” <<
b.topSecret;
cout << “\nThe sum of values of topSecret in myClass1 and
myClass2 is ” << a.topSecret + b.topSecret;
}
This is an interesting function. Despite not being the member of any class, it can
access
the data of both the classes. This function is friend of both the classes.
Here is the complete code of the program.
/*
A sample program showing the use of friend function,
which access the private data members of two classes.
*/
#include <iostream.h>
class myClass2; // declaring the class for the friend function in myClass1
// definition of the myClass1
class myClass1
{
// private data members. Hidden
private:
int topSecret;
// interface of the class
public:
void display() { cout << "\nThe value of the topSecret is " << topSecret; }
myClass1();
// friend function
friend void addBoth(myClass1, myClass2);
};
// definition of the constructor.
myClass1::myClass1()
{
topSecret = 100;
}
// Definition of the myClass2
Page 370
class myClass2
{
// private data members. Hidden
private:
int topSecret;
// interface of the class
public:
void display() { cout << "\nThe value of the topSecret is " << topSecret; }
myClass2();
// friend function
friend void addBoth(myClass1, myClass2);
};
// definition of the constructor.
myClass2::myClass2()
{
topSecret = 200;
}
// The definition of the friend function which is adding the topSecret data member
of both
the classes.
void addBoth(myClass1 a, myClass2 b)
{
cout << "\nThe value of topSecret in the myClass1 object is " <<
a.topSecret;
cout << "\nThe value of topSecret in the myClass2 object is " <<
b.topSecret;
cout << "\nThe sum of values of topSecret in myClass1 and
myClass2 is " << a.topSecret + b.topSecret;
}
// main program
void main()
{
// declaring the objects and displaying the values
myClass1 a;
myClass2 b;
a.display();
b.display();
// calling friend function and passing the objects of both the classes
addBoth(a, b);
}
Page 371
The output of the program is;
The value of the topSecret is 100
The value of the topSecret is 200
The value of topSecret in the myClass1 object is 100
The value of topSecret in the myClass2 object is 200
The sum of values of topSecret in myClass1 and myClass2 is 300
The classes have defined and declared this function
addBoth to be a friend.
In each class,
we have declared it as a friend function. This function cannot declare itself a
friend
function for these classes from outside. So be careful about this as a class declares
its
friend functions. A function out side the class cannot declare itself a friend of
the class.
The friend functions are not used very often.
Sample Program 3
Now we can expand our previous example. We can define functions
subBoth, mulBoth
and divBoth as friend
functions of the class, in addition of
addBoth function. These
friend
functions can manipulate the data members of the class.
Following is the code of the example that shows the usage of friend functions.
/* The following program demonstrate the declaration and uses of friend functions
of a
class
We set values in the constructors of the classes. The program prompts the user to
enter a
choice of addition, subtraction, multiplication or division. And then performs the
appropriate
operation by using the friend functions.
*/
#include <iostream.h>
#include <stdlib.h>
class myClass2; // declaration of the myClass2 for the friend functions
class myClass1
{
private:
float value ;
public:
myClass1 ( )
{
value = 200 ;
}
// friend functions
friend float addBoth ( myClass1, myClass2 ) ;
Page 372
friend float subBoth ( myClass1, myClass2 ) ;
friend float mulBoth ( myClass1, myClass2 ) ;
friend float divBoth ( myClass1, myClass2 ) ;
};
class myClass2
{
private:
float value ;
public:
myClass2 ( )
{
value = 100 ;
}
// friend functions
friend float addBoth ( myClass1 , myClass2 ) ;
friend float subBoth ( myClass1 , myClass2 ) ;
friend float mulBoth ( myClass1 , myClass2 ) ;
friend float divBoth ( myClass1 , myClass2 ) ;
};
void main ( )
{
myClass1 myClass1Obj ; //create an object of class myClass1
myClass2 myClass2Obj ; //create an object of class myClass2
char choice;
cout << "Please enter one of the operator +, -, /, * " << "followed by Enter " <<
endl;
cin >> choice;
if ( choice == '+' )
{
cout << "The sum is : " << addBoth(myClass1Obj , myClass2Obj) << endl;
}
else if ( choice == '-' )
{
cout << "The difference is : " << subBoth(myClass1Obj , myClass2Obj) << endl;
}
else if ( choice == '*' )
{
cout << "The multiplication is : " << mulBoth(myClass1Obj , myClass2Obj) <<
endl;
}
else if ( choice == '/' )
Page 373
{
cout << "The division is : " << divBoth(myClass1Obj , myClass2Obj) << endl;
}
else
{
cout << "Enter a valid choice next time. The program is terminating" << endl;
}
system ( "PAUSE" ) ;
}
float addBoth ( myClass1 object1 , myClass2 object2 )
{
return ( object1.value + object2.value ) ;
}
float subBoth ( myClass1 object1 , myClass2 object2 )
{
return ( object1.value - object2.value ) ;
}
float mulBoth ( myClass1 object1 , myClass2 object2 )
{
return ( object1.value * object2.value ) ;
}
float divBoth ( myClass1 object1 , myClass2 object2 )
{
return ( object1.value / object2.value ) ;
}
Following is the output of the program.
Please enter one of the operator +, -, /, * followed by Enter
*
The multiplication is : 20000
Friend Classes
We have seen that a class can define friend functions for itself. Similarly a class
can be
declared as a friend class of the other class. In that case, the function of a class
gets
complete access to the data members and functions of the other class. So it is an
interesting expansion of the definition that not only the functions but also a class
can be a
friend of the other class. The syntax of declaring a friend class is that within
the class
definition, we write the keyword
friend with the name of
the class. It is going to be a
friend class. i.e. friend class-name;
We can also write the word class after the keyword friend and before the class name
as
friend class class-name ;
Page 374
Now let’s take another example of a class. Suppose, we have classes
ClassOne and
OtherClass. We want to make
OtherClass a friend class
of the ClassOne.
So we declare
OtherClass a friend class in the definition of the
ClassOne as following.
class ClassOne
{
friend OtherClass ;
private:
//here we write the data members of ClassOne
};
The line
friend OtherClass ;
can also be written as
friend class OtherClass ;
The line friend OtherCalss;
explains that OtherClass
is a friend of ClassOne.
If
OtherClass is the friend of
ClassOne, all the functions
of OtherClass will
have access to
all the inside part of ClassOne.
The following code segment shows the declaration of friend class. It shows that
OtherClass is a friend of
ClassOne so it has access
to the private data of ClassOne.
class ClassOne
{
friend class OtherClass;
private:
int topSecret;
};
class OtherClass
{
public:
void change( ClassOne co )
};
void OtherClass::change( ClassOne co )
{
co.topSecret++; // Can access private data of class one
}
The friend keyword
provides access in one direction only. This means that while
OtherClass is a friend of
ClassOne, the reverse is
not true. Here ClassOne
declares that
OtherClass is my friend. But it does not work the other way. It does
not mean that
ClassOne has access to the inside data members and methods of
OtherClass. Thus, it is
a
one way relationship i.e. the
OtherClass can look into
ClassOne, but
ClassOne cannot
Page 375
look inside OtherClass.
If we want a two-way relationship,
OtherClass will have to
declare ClassOne
as a friend class, resulting in a complete two-way relationship.
Like functions, a class cannot declare itself a friend of some other class. A class
can
declare its friend classes in its declaration and cannot be a friend of other classes
by
declaring itself their friend. In the above example,
ClassOne declares that
OtherClass is
my friend class. So otherClass
can access all the data members and methods (private,
public or utility functions) of
ClassOne. It does not (and
cannot) declare that I
(ClassOne) am a
friend class of OtherClass.
So ClassOne has
no access to private data
members and methods of OtherClass.
It can access these only if
OtherClass declares
ClassOne as its friend. This means that by using the keyword friend,
a class gives rights
of accessing its data members and methods to other classes and does not get the
rights to
access other classes.
By declaring friend functions and classes, we negate the concept of data hiding
and data
encapsulation and show the internal structure of the class to the friends. But the
good
thing in it is that a class declares its friends while the other functions or classes
cannot
look inside the class. The disadvantage of friend classes is that if we declare
such a
relationship of friendship for two classes, this will become a pair of classes.
To explain it
we go back to the concept of separating the interface and implementation. In case
of
change in the implementation of
ClassOne, the private data
structure will also change.
For example, at first we have an integer variable
int i; and later, we need
two more
variables and we write it as
int j, k, l; As the implementation of
ClassOne has now
changed, the functions of OtherClass
that wanted to manipulate the members of
ClassOne will not work now. It is critically important that friend classes
should be
declared very carefully. When is it necessary? This can be understood by an example
from mathematics. We have straight line in math. The equation of straight line is:
y = mx
+ c. Here m is the
slope of line i.e. the angle which the line makes with x-axis. And
c is
the intercept at y-axis. So if we have to define a straight line, there is need
of two
numbers i.e. m and
c. Now if we have
to define a class StraightLine,
the private data of it
will be double m, c;
or let’s use the names which are self explanatory like
double slope,
intercept; And then in the class, there will be the methods of the class.
We can write it as
calss StraightLine
{
//some methods
private:
double slope, intercept ;
};
Now we can also have another class quadratic that also belongs to mathematics. Suppose,
we have a parabola, the equation of which is y= ax2 + bx + c. Where
a, b and c, for the
time being, are real constants. To define this quadratic equation as class, we have
to
define the three coefficients a, b and c. The statement will be as under:
class Quadratic
{
//some methods
Page 376
private:
double a, b, c ;
};
Now we have two classes i.e. StraightLine and Quadratic. In a mathematical problem,
when we have given a parabola (a quadratic equation) and a straight line (straight
line
equation) and are asked to find the point at which the straight line intersects
the parabola.
To solve it, we setup equations and solve them simultaneously and find out the result,
which may be in three forms. Firstly, there is the line that does not intersect
the parabola.
The second is that it intersects the parabola at one point (i.e. it is a tangential
line) and
third may be that the line intersects the parabola at two points.
When we setup these equations, we come to know that here the constants
m, c(of straight
line), a, b and
c of quadratic equation
are being used. So from a programming perspective
if we had an object l1 of type StraighLine and an object q1 of type quadratic. And
wanted
to find the intersection of l1 with q1. Now here is a situation where we need either
a
friend function of both classes, so that it can manipulate the data of both classes,
or need
to declare both classes as friend classes of each other and then write their methods
to find
the intersection. Similarly we can have many other examples in which a class may
need
to look into the other class. But it is not some thing to be done all the time.
It should be
done only when necessary. Use of friend functions is normally a better idea. Using
friend
classes means that both the classes are linked with each other. If the code in any
one of
the class is modified i.e. its implementation is changed, we have to recompile both
the
classes. Due to change in one class, the other class also needs to be changed,
necessitating the compilation of both the classes.
So we have lost the principle of separating the interface from the implementation.
Now
let’s talk about the limitations of this friendship business. Firstly, there is
no transitive
dependency in friend declarations. Suppose I say
student A is my friend
and being a
friend he knows my thoughts and ideas. Now the
student A says ”student
B is my friend”
i.e. student B knows
thoughts and ideas of student
A. Does it mean that
student B is also
my friend? Does student B
knows my thoughts and ideas? The answer is no. As I have
not declared student B
a friend of mine, so he (student
B) does not know about my
thoughts and ideas. The same applies to the
friend definition for classes.
The friendship is
not transitive. It is not like ‘A is a friend of B and B is a friend of C, therefore
A is a
friend of C‘. It does not work. A has to specifically declare ‘B is my friend and
C is my
friend’ to make B and C friends of him. There is no transitive dependency in friend
declarations.
Secondly, I can declare you to be my friend. This means I have unveiled my thoughts
and
ideas to you. But I cannot get your thoughts and ideas unless you declare me a friend
of
yours. So there is no association, which means A saying B is my friend does not
imply in
any way that A is a friend of B. Here B is a friend of A. But B has to declare ‘A’
its
friend. Thus the friend
keyword produces one-way relationship.
Page 377
Summary
The concept of classes allows us to separate implementation from interface.
A class is a user defined data type. In a class, we declare private data members
and utility
functions so that they cannot be access from outside. Similarly, we declare some
parts of
the class public
that become the interface for the class and can be accessed from the
outside. These interface methods or public methods can manipulate the data of the
class.
This is the encapsulation and data hiding.
We have the concept of friend functions. By declaring an external function as a
friend
function, that function gets the complete access to the inner structure of the class
including all private data. When classes need to be interactive, these must be declared
friends of each other. Thus we have the concept of friend classes. The use of friend
function and class is a useful feature that sometimes we need to use. But we should
use it
very sparingly and carefully as it basically negates the concepts of encapsulation
and data
hiding.
The principles of friendship of functions and classes are that the friendship is
granted, not
taken. So a class declares its friend functions and friend classes. If a class declares
another class as a friend, it is not always reciprocal. So declaration and granting
of a right
is one way. The owner of the right grants it. So the class itself grants the privilege
of
access to outsider functions or to other classes. It is not transitive. It does
not go ‘A is a
friend of B and B is a friend of C therefore A is a friend of C’. It does not work
that way.
It is restricted to a one-step relationship. If A is a friend of B, and B is a friend
of C. If A
wants C to be a friend, it has to declare, “C is my friend”.
|
|
|
|