In this article I am going to write about virtual function – another type of polymorphism. Polymorphism is another essential feature of an Object – Oriented Programming language. It is the polymorphism that enables us to deal with different types of object as if they are all of the same type. We have already seen two types of polymorphism – function overloading and operator overloading. The third type of polymorphism simplifies the syntax of performing the same operation with different classes through virtual functions.
This type of polymorphism simplifies the syntax of performing the same operation with a hierarchy of classes. With the help of polymorphism we can easily keep the interface to the classes clearly. And in this case we do not need to have unique function names for similar operation on each derived classes. This type of polymorphism is supported by virtual keyword. For the new C++ programmer the concept of virtual function may be difficult to understand. But it would be harmful if you skip this topic because there is no analog to virtual function in procedural languages. Thus just read on, the concept of virtual function would soon become clearer.
Virtual Functions
Let us understand this concept by taking a simple program – v1.cpp that has normal member functions in base class as:
// Program – v1.cpp: Without virtual function
#include
class father
{
public:
void display()
{
cout<< “\nI am your father”;
}
};
class baby1 : public father
{
public:
void display()
{
cout << “\nI am your first baby”;
}
};
class baby2 : public father
{
public:
void display()
{
cout << “\nI am your second baby”;
}
};
void main()
{
baby1 b1;
baby2 b2;
father *fptr;
fptr=&b1;
fptr-> display();
fptr=&b2;
fptr -> display;
}
In this program we have derived two classes baby1 and baby2 from the base class father. Each of these three classes has a number functions display (). In main () we have created two objects b1 and b2 from two derived classes baby1 and baby2 respectively and a pointer fptr to base class father.
In first assignment statement we have
fptr =&b1;
Should this not give us an error, since we are assigning an address of one type to a pointer of another? No, because unlike normal pointers, the compiler does not flash an error message. In inheritance a pointer or a reference to a base class type can refer to an object of a derived class type. In this case the pointers to object of a derived class are type compatible with pointer to objects of the base class. Such type of casting is called a upcasting. Similarly a reference to base is compatible with any object of a derived class.
When we execute next statement
fptr-> display()
One may ask - Which function gets called – display() of derived class baby1 or display () of base class, father.
The same question arises in the last statement
fptr-> display()
In these cases the function in the base class gets called. Thus when we execute this program we get the following output….
I am your father
I am your father
It happens so because the compiler ignores the contents of the pointer and selects the member function that matches the type of the pointer. It is good sometimes but it is does not like that what we have discussed at the beginning of this article that is accessing functions of different classes using the same statement. Here we are going to discuss the concept of polymorphism, in which we manipulate more than one derived type with a base class pointer or reference.
If we make a small change in this program by using the keyword virtual in front of the function display() in the base class, we can get the desired output.
Program v2.cpp illustrates this concept.
// Program – v2.cpp : With virtual function
#include
class father
{
public:
virtual void display()
{
cout << “\nI am your father”;
}
};
class baby1 : public father
{
public:
void display()
{
cout << “\nI am your first baby”;
}
};
class baby2 : public father
{
public:
void display()
{
cout << “\nI am your second baby”;
}
};
void main()
{
baby1 b1;
baby2 b2;
father *fptr;
fptr=&b1;
fptr-> display();
fptr=&b2;
fptr ->display();
}
Now if we execute this program, the out put will be as:
I am your first baby
I am your second baby
Using a base class pointer, when we refer to any member function it retrieves the actual derived type of an object. From the output of this program, it is clear that the same function call
fptr->display ();
executes different functions, depending on the contents of fptr.
Thus a non virtual pointer sets up in any derived class always points to the member function in the base class only. Whereas when virtual functions are defined, the virtual pointer points to member function of the derived class. That’s why in this program the compiler has selected the function based on the contents of the pointer fptr, not on the type of the pointer.
When the compiler compiles this program, it does not know which object’s address fptr may contain. It could be the address of an object of the baby1 class or of the baby2 class. So it does not know which version of display() would get called. In this case the compiler leaves the decision until the program is running. At run time after receiving the address of an appropriate object, it calls the appropriate function. This is called late binding or dynamic binding. On the other hand if the functions are chosen during compile time, the binding is called as early or static binding.
We can also achieve the same by using references instead of pointer as:
// Program – v3.cpp : With virtual function
#include
class father
{
public:
virtual void display()
{
cout << “ I am your father”;
}
};
class baby1 : public father
{
public:
void display()
{
cout << “I am your first baby”;
}
};
class baby2 : public father
{
public:
void display()
{
cout << “I am your second baby”;
}
};
void main()
{
baby1 b1;
baby2 b2;
father &f1ref=b1;
f1ref.display();
father &f2ref=b2;
f2ref.display();
}
When we execute this program, we get the same output as previous one.
Pure Virtual Function
A pure virtual function is a virtual function with no body. In a situation, where the function of the base class are not used we use the notation=0 in the function declaration.
For example the statement
virtual void display()=0;
declare the function display() to be a pure virtual function. Here the value 0 is not assigned to anything. It is used to simply tell the compiler that function will be pure that is have no body.
Here any intelligent person may think that if we remove the body of the virtual function then can we not remove the function of together? But unfortunately it would be wrong. Because without a function display() in base class, the statement like
fptr-> display()
would be invalid. Since fptr is a pointer to a base class. And we know that a base class does not have any knowledge of its derived class’s members.
Program v4.cpp illustrates this concept of pure virtual function.
// Program – v4.cpp : Pure virtual function
#include
class father
{
public:
virtual void display()=0;
};
class baby1 : public father
{
public:
void display()
{
cout << “I am your first baby”;
}
};
class baby2 : public father
{
public:
void display()
{
cout << “I am your second baby”;
}
};
void main()
{
baby1 b1;
baby2 b2;
father &f1ref=b1;
father &f2ref=b2;
f1ref.display();
f2ref.display();
}
A More Practical Example
We have already seen that an upcasting can convert a pointer that referes to an object of class type to a pointer to a class in the same class hierarchy. It is achieved by using virtual functions. A virtual function appears to exits but does not exist in reality. A virtual function is defined and declared in the base class as being virtual. It is then used by several derived functions by setting up pointers.
Let us assume that our program defines a class library to represent the different areas of shape. Let we have two different classes called Triangle and Rectangle. Each of these two classes has a member function area_display() to display the are of relevant shape on the screen. If we want to display the are of numerous triangles and rectangles, we can create an array that holds pointers to all the different objects in the class hierarchy.
The array might be defined as:
Shape * sptr[5];
And if we want to display the areas of different shapes, we will use the following loop:
for(i=0; i<20; i++)
sptr[i]->area_display();
Earlier we have seen that how the same function call is responsible for the execution of completely different function. It means that when sptr[i] contains address of the Triangle object, it would call
Triangle :: area_display()
function. When it contains the address of the Rectangle object it would call the
Rectangle :: area_display()
function. It happens so because the array sptr[] has been defined to contain shape pointer and not triangle or rectangle pointers. This concept is called the polymorphism. Here the functions have the same name, area_display(), but different functions from different classes are executed. And it depends upon the contents of sptr [i]
To achieve this, following conditions must be met:
- All the different classes Triangle and Rectangle must be derived from a single base class, Shape.
- The area_display() function must be declared to be virtual in the base class, Shape. Once a function is declared virtual in a base class, its definition remains virtual in all derived classes; even when the keyword virtual is not repeated in the definition of the derived class.
For this we define a base class Shape and from this base class we derive two classes Triangle and Rectangle as:
class Shape
{
// ….
};
class Triangle : public Shape
{
// ….
};
class Rriangle : public Shape
{
// ….
};
Now let us see how to implement this in practical use.
Let we create a base class Shape which stores two double type data members that could be used to compute the area of figure. From this base class, we derive two classes Triangle and Rectangle. In base class we define a member function getdata() to initialize base class data members and another member function area_display() to compute and display the area of figure. Make the function area_display() as a virtual function and redefine these functions in the derived classes to match their requirements.
In case of Triangle class, these two values of base class will treated as base and height whereas in Rectangle these two values of base class will treated as length and breadth of rectangle. The area is computed as:
Area of triangle = (x0 * y0) / 2;
Area of rectangle = x0 * y0;
Following program does this.
// Program – v5.cpp
#include
class Shape
{
protected :
double x0, y0;
public :
void getdata(double x, double y)
{
x0 = x;
y0 = y;
}
virtual void area_display() = 0;
};
class Triangle : public Shape
{
public :
void getdata(double x, double y)
{
Shape :: getdata(x,y);
}
void area_display()
{
double area = (x0 * y0)/2.0;
cout << "\n Area of triangle = " << area;
}
};
class Rectangle : public Shape
{
public :
void getdata(double x, double y)
{
Shape :: getdata(x,y);
}
void area_display()
{
double area = (x0 * y0);
cout << "\n Area of rectangle = " << area;
}
};
void main()
{
Triangle *tptr;
Rectangle *rptr;
Shape *sptr[2];
int i;
tptr = new Triangle;
rptr = new Rectangle;
tptr->getdata(20.0,30.0);
rptr->getdata(20.0,20.0);
sptr[0] = tptr;
sptr[1] = rptr;
for(i=0; i<2; i++)
sptr[i]->area_display();
}
The output of this program is
Area of triangle =300
Area of rectangle =400
Abstract Classes
In program v5.cpp we have not created any object of class Shape because there is no need to make objects of Shape class. Here Shape class is used just to derive Triangle and Rectangle classes. Such class is known as an abstract class.
Thus an abstract class is a class which is not used to create any objects, rather than it is used to derive the classes. An abstract classes one that contain at least one pure virtual function and it defines properties common to other classes derived from it. We can also create a pointer or a reference to an abstract class. This allows an abstract class to be used as a base class, pointers to which can be used to select the proper virtual function.
Here one should remember that it is necessary to override a pure virtual function in all the derived classes from this abstract class. If you do not override then the derived class is also treated as an abstract class. However if you try to create an object of the abstract class then the compiler will certainly flag an error message.
For example, if you try to execute the following program
// Program - v6.cpp
#include
class Father
{
public :
virtual void display() = 0;
};
class Baby1 : public Father
{
};
class Baby2 : public Father
{
};
void main()
{
Father *fptr;
Baby1 b1;
Baby2 b2;
fptr = &b1;
fptr->display();
fptr = &b2;
fptr->display();
}
then the compiler reports the following error messages:
Cannot create instance of abstract class 'Baby1'
Cannot create instance of abstract class 'Baby2'
Here one should remember that an object of a derived class can be assigned to a base class object. When you do this, the compiler copies only the base portion of the derived object. It means that it has no knowledge of data members or member functions which are defined in derived classes only.
For example let we have a base class First, which has two data members a and b and a derived class Second also has two data members c and d. It means that the derived class Second now has total four data members whereas the base class First has only two. Now if you assign the object of a derived class Second to an object of base class First then it simply copies a and b of Second class object and truncates the derived portion of the derived object, which is c and d. It happens so because there is no way to find in advance that a derived class can have how many number of data members in advance.
Following program illustrates this concept.
// Program - v7.cpp
#include
class First
{
protected :
int a, b;
public :
First(int aa=0, int bb=0)
{
a=aa;
b=bb;
}
virtual void display()
{
cout << "\n" << a << "\t" << b;
}
};
class Second : public First
{
private :
int c, d;
public :
Second(int aa=0, int bb=0, int cc=0, int dd=0) : First(aa,bb)
{
c=cc;
d=dd;
}
virtual void display()
{
cout<<"\n"<<<"\t"<<<"\t"<<<"\t"<
}
};
void main()
{
First f(10,20);
Second s(100,200,300,400);
f.display();
s.display();
f=s;
f.display();
}
#include
class Father
{
public :
virtual void display() = 0;
};
class Baby1 : public Father
{
public :
void display()
{
cout << "\nI am derived from Father.";
}
void child1()
{
cout << "\nI am pure baby 1.";
}
};
class Baby2 : public Father
{
public :
void display()
{
cout << "\nI am derived from Father.";
}
void child2()
{
cout << "\nI am pure baby 2.";
}
};
void main()
{
Father *fptr;
Baby1 b1;
Baby2 b2;
fptr = &b1;
fptr->display();
fptr->child1();
fptr = &b2;
fptr->display();
fptr->child2();
}
#include
class Father
{
public :
virtual void display() = 0;
virtual void child() = 0;
};
class Baby : public Father
{
public :
void display()
{
cout << "\nI am derived from Father.";
}
void child1()
{
cout << "\nI am pure baby.";
}
};
void main()
{
Father *fptr;
Baby b;
fptr = &b;
fptr->display();
fptr->child();
}
#include
#include
class Father
{
public :
Father()
{
cout << "\nFather Constructor.";
}
~Father()
{
cout << "\nFather Destructor.";
}
};
class Baby : public Father
{
public :
Baby()
{
cout << "\nBaby Constructor.";
}
~Baby()
{
cout << "\nBaby Destructor.";
}
};
void main()
{
Father *fptr;
Baby *bptr = new Baby;
fptr = bptr;
delete fptr;
}
delete fptr;
virtual ~Father()
{
cout << "\nFather Destructor.";
}
Program – v11.cpp illustrates the use of virtual destructor.
// Program - v11.cpp
#include
#include
class Father
{
public :
Father()
{
cout << "\nFather Constructor.";
}
virtual ~Father()
{
cout << "\nFather Destructor.";
}
};
class Baby : public Father
{
public :
Baby()
{
cout << "\nBaby Constructor.";
}
~Baby()
{
cout << "\nBaby Destructor.";
}
};
void main()
{
Father *fptr;
Baby *bptr = new Baby;
fptr = bptr;
delete fptr;
}
#include
class Father
{
public :
virtual void display()
{
cout << "\nBase class virtual function.";
}
};
class Baby1 : public Father
{
};
class Baby2 : public Father
{
};
void main()
{
Father *fptr;
Baby1 b1;
Baby2 b2;
fptr = &b1;
fptr->display();
fptr = &b2;
fptr->display();
}
#include
class Second;
class First
{
private :
int i;
public :
First ()
{
i=10;
}
friend int funny(const First &ff, const Second &ss);
};
class Second
{
private :
int j;
public :
Second ()
{
j=15;
}
friend int funny(const First &ff, const Second &ss);
};
int funny(const First &ff, const Second &ss)
{
int temp;
temp = ff.i+ss.j;
return temp;
}
void main()
{
First f;
Second s;
int data;
data = funny (f, s);
cout << data;
}
friend int funny(const first &ff, const second &ss);
#include
class Second;
class First
{
private :
int i;
public :
First()
{
i = 10;
}
friend Second;
};
class Second
{
private :
int j;
public :
Second()
{
j = 20;
}
void putdata(First ff)
{
cout << "\n" << ff.i << "\t" << j;
}
void display(First ff)
{
cout << "\n" << ff.i << "\t" << j;
}
};
void main()
{
First f;
Second s;
s.putdata(f);
s.display(f);
}
In this program, we have declared an entire class Second as friend in class First:
class Second;
#include
class Distance
{
private :
int meter;
float cm;
public :
Distance ()
{
meter = 0;
cm = 0;
}
Distance (float mm)
{
meter = int (mm);
cm = (mm - meter) * 100;
}
Distance (int mm, float cc)
{
meter = mm;
cm = cc;
}
void display()
{
cout <<"\nMeter = "<<<"\nCentimeter = "<< cm;
}
Distance operator + (const Distance &);
};
Distance Distance :: operator + (const Distance &dd)
{
Distance temp;
temp.meter = meter + dd.meter;
temp.cm = cm + dd.cm;
if (temp.cm >= 100)
{
temp.meter++;
temp.cm -= 100;
}
return temp;
}
void main ()
{
Distance d1(20, 45.85), d2, d3, d4;
d2 = 70.65; // one argument constructor
d1.display();
d2.display();
d3 = d1 + 70.55; // Distance + float : O.K.
d3.display();
d4 = 50.25 + d2; // float + Distance : ERROR
d4.display();
}
d3 = d1 + 70.55;
This translate to the following function call,
d3 = d1.operator + (70.55);
d4 = 50.25 + d2;
d4 = 50.25 . operator + ();
friend Distance operator + (float dist, const Distance &dd);
Distance operator + (float dist, const Distance &dd)
{
return dd+dist;
}
Now when compiler encounters the statement
d4 = 50.25 + d2;
the friend function translates this statement into the following statement
d4 = d2 + 50.25;
friend Distance operator + (const Distance &dd1, const Distance &dd2);
This friend function is defined as:
Distance Distance :: operator + (const Distance &dd1, const Distance &dd2)
{
Distance temp;
temp.meter = dd1.meter + dd2.meter;
temp.cm = dd1.cm + dd2.cm;
if (temp.cm >= 100)
{
temp.meter++;
temp.cm -= 100;
}
return temp;
}
From this definition it is clear that a friend function always requires one more argument than equivalent normal member function. Thus the statement
d3 = d1 + d2;
is interpreted as:
d3 = d2 . operator + (d1);
// if the operator function is defined as a normal member function
and d3 = operator + (d1, d2);
// if the operator function is defined as a friend function
Thus in friend function the extra argument represents the object that a normal member function uses implicitly.
Following program shows how this can be achieved.
// Program – v16.cpp
#include
class Distance
{
private :
int meter;
float cm;
public :
Distance()
{
meter = 0;
cm = 0;
}
Distance(float mm)
{
meter = int (mm);
cm = (mm - meter) * 100;
}
Distance(int mm, float cc)
{
meter = mm;
cm = cc;
}
void display()
{
cout <<"\nMeter = "<<<"\nCentimeter = "<< cm;
}
friend Distance operator + (const Distance &dd1, const Distance&dd2);
};
Distance operator + (const Distance &dd1, const Distance &dd2)
{
Distance temp;
temp.meter = dd1.meter + dd2.meter;
temp.cm = dd1.cm + dd2.cm;
if (temp.cm >= 100)
{
temp.meter++;
temp.cm -= 100;
}
return temp;
}
void main ()
{
Distance d1 (20, 45.85), d2, d3, d4;
d2 = 70.65; // one argument constructor
d1.display();
d2.display();
d3 = d1 + 70.55; // Distance + float : O.K.
d3.display();
d4 = 50.25 + d2; // float + Distance : O.K.
d4.display();
}
Here is the output of this program….
Meter = 20
Centimeter = 45.85
Meter = 70
Centimeter = 65
Meter = 91
Centimeter = 0.85
Meter = 120
Centimeter = 90
In earlier version of this program the overloaded + operator took only one argument, whereas in this program it takes two arguments. This is because in earlier program, one of the object on which the + operator is the object of which it was a member, and the second is an argument. And in this program the operator function is no longer a member function of the class, rather than it is a friend of the class Distance.
A more Practical Example
Now let us see another example of friend function. Let we create two classes DM and DF which stores the value of Distances. The DM class stores Distance in meters and cm and DF in feet and inches. Here we would write a friend function that adds one object of DM with another object of DF. The object that stores the result may be DM object or DF object. The output should be in the format of meter and cm or feet and inches depending on the objects on the display.
// Program – v17.cpp
#include
const float MTFT = 3.280833;
class DM;
class DF
{
private :
int feet;
float inches;
public :
DF()
{
feet = 0;
inches = 0;
}
DF(int ff, float hh)
{
feet = ff;
inches = hh;
}
void getdist()
{
cout << "\nEnter Feet = ";
cin >> feet;
cout << "Enter Inches = ";
cin >> inches;
}
void display()
{
cout << "\nFeet = " << feet;
cout << "\nInches = " << inches;
}
friend DM operator + (DM,DF);
};
class DM
{
private :
int meter;
float cm;
public :
DM()
{
meter = 0;
cm = 0;
}
DM(int mm, float cc)
{
meter = mm;
cm = cc;
}
void getdist()
{
cout << "\nEnter Meter = ";
cin >> meter;
cout << "Enter Centimeter = ";
cin >> cm;
}
void display()
{
cout << "\nMeter = " << meter;
cout << "\nCentimeter = " << cm;
}
operator DF()
{
int ft;
float inch, temp;
temp = (meter+cm/100)*MTFT;
ft = int(temp);
inch = (temp-ft)*12;
return DF(ft,inch);
}
friend DM operator + (DM,DF);
};
DM operator + (DM d1, DF d2)
{
DM temp;
float t;
t = d2.feet+(d2.inches)/12;
t /= MTFT;
temp.meter = d1.meter + int (t);
temp.cm = d1.cm + (t-int(t))*100;
return temp;
}
void main()
{
DM d1,d2;
DF d3,d4;
cout << “\nEnter first Distance in meter and centimeter.”;
d1.getdist();
cout << “\nEnter second Distance in feet and inches.”;
d3.getdist();
d2 = d1+d3;
d4 = d1+d3;
cout << “\nAddition of two Distance in meter and centimeters.”;
d2.display();
cout << “\nAddition of two Distance in feet and inches.”;
d4.display();
}
The output of this program is
Enter first Distance in meter and centimeter.
Enter Meter =10
Enter Centimeter =50
Enter second Distance in feet and inches.
Enter Feet = 20
Enter Inches = 11.75
Addition of two Distance in meter and centimeters.
Meter = 16
Centimeter = 89.446304
Addition of two Distance in feet and inches.
Feet =55
Inches = 5.134964
Overloaded Operators:
Overloading the
In earlier programs we have used getdist() and display() functions to read Distance objects and write Disaply objects on the console. Now one may ask – Can’t we read user-defined objects as cin >> d1; or display user-defined object, such as cout and << operators to perform input/output for user-defined data types.
No doubt, these two operators are heavily overloaded. The standard ostream class overloads the << operator to send its objects whatever arguments the overloaded operator function receives. Remind that cout is a standard ostream object that is smart enough to recognize all the basic C++ data types. The ostream class has following overloaded operator functions:
ostream & operator << (char c);
ostream & operator << (unsigned char c);
ostream & operator << (signed char c);
ostream & operator << (short n);
ostream & operator << (unsigned short n);
ostream & operator << (int n);
ostream & operator << (unsigned int n);
ostream & operator << (float n);
ostream & operator << (double n);
ostream & operator << (long double n);
ostream & operator << (long n);
ostream & operator << (unsigned long n);
ostream & operator << (bool b);
ostream & operator << (const char *s);
ostream & operator << (const unsigned char *s);
ostream & operator << (const signed char *s);
On similar track, the istream overloads >> operator for all the basic C++ data types. If you want to use operators on user-defined data types then it is necessary to overload operators. The << operator is overloaded as:
ostream & operator << (ostream &os, const class_name &cobj)
{
os << …. // display object’s contents
return os;
}
Similarly, the >> operator is overloaded as:
istream & operator >> (istream &is, class_name &cobj)
{
is >> ….; // read object’s contents
return is;
}
Here class_name is the name of the class whose object is to read or display. Both of these functions return a reference to an ostream object and istream object. However it is not mandatory, but generally the overloaded >> operator functions should be made friend functions when they are used to read and write user-defined objects.
For example, if we want to read and display Distance class object then we will overload these operators as:
istream & operator >> (istream &is, Distance &dd)
{
is >> dd.meter >> dd.cm;
return is;
}
and
ostream & operator << (ostream &os, const Distance &dd)
{
os << "\nMeter = " << dd.meter << "\nCentimeter = " << dd.cm;
return os;
}
Program v18.cpp shows the usage of these two overloaded operator functions.
// Program – v18.cpp
#include
class Distance
{
private :
int meter;
float cm;
public :
Distance(int mm=0, float cc=0.0)
{
meter=mm;
cm=cc;
}
friend ostream & operator << (ostream &os, const Distance &dd);
friend istream & operator >> (istream &os, Distance &dd);
};
ostream & operator << (ostream &os, const Distance &dd)
{
os << "\nMeter = " << dd.meter << "\tCentimeter = " << dd.cm;
return os;
}
istream & operator >> (istream &is, Distance &dd)
{
is >> dd.meter >> dd.cm;
return is;
}
void main()
{
Distance d;
cout << "Enter meters and centimeter = ";
cin >> d;
cout << d;
}
Here is the output of this program….
Enter meters and centimeter = 40 30.75
Meter =40 Centimeter = 30.75
In this program we have defined two friend functions operator (). Since these functions access the private members of Distance class only, not the private members of ostream class. Therefore these functions are declared as friends in Distance class only.
Here when the compiler encounters the statements
cin >> d; and
cout << d;
they are converted into the following statements:
operator >> (cin, dd); and
operator << (cout, dd);
respectively. Another main point to note is that the objects in these operator functions are collected as reference, in order to prevent creation of another copies of these objects. These operator functions returns the istream and ostream object by reference to permit cascading, such as:
cin >> d1 >> d2; and
cout << d1 << d2;
Friends or No Friends
Is it always necessary to declare operator () functions as friend functions? Its answer is no. If they access the private members of both classes directly then these functions should be friends to both classes. If these two operator functions access the private data members of either class then it is necessary to define these two functions as a friend function in that particular class.
If we look at the last program then it is clear that these functions access the private data members of Distance objects directly but only uses the istream and ostream objects as a whole. Therefore it is necessary to define these two functions friend to Distance class only, not in istream and ostream class. However if these two operator functions do not access data member functions directly then there is no need to declare them friends in either class. For example, let we overload these operator functions as:
ostream & operator << (ostream &os, Distance &dd)
{
os << "\nMeter = " << dd.getmeter() << "\nCentimeter = " << dd.getcm();
return os;
}
istream & operator >> (istream &is, Distance &dd)
{
int mm;
float cc;
is >> mm >> cc;
dd.setdist(mm,cc);
return is;
}
where getmeter(), getcm() and setdist() are member functions which are defined in Distance class as:
void setdist(int mm, float cc)
{
meter = mm;
cm = cc;
}
int getmeter()
{
return meter;
}
float getcm()
{
return cm;
}
Following program illustrates this concept.
// Program – v19.cpp
#include
class Distance
{
private :
int meter;
float cm;
public :
Distance(int mm=0, float cc=0.0)
{
meter=mm;
cm=cc;
}
void setdist(int mm, float cc)
{
meter = mm;
cm = cc;
}
int getmeter()
{
return meter;
}
float getcm()
{
return cm;
}
};
ostream & operator << (ostream &os, Distance &dd)
{
os << "\nMeter = " << dd.getmeter() << "\nCentimeter = " << dd.getcm();
return os;
}
istream & operator >> (istream &is, Distance &dd)
{
int mm;
float cc;
is >> mm >> cc;
dd.setdist(mm,cc);
return is;
}
void main()
{
Distance d;
cout << "Enter meters and centimeter = ";
cin >> d;
cout << d;
}
Here is the output of this program….
Enter meters and centimeter = 30 50.75
Meter = 30
Centimeter = 50.75