<Previous Lesson

Introduction to Programming

Next Lesson>

Lesson#37

Lesson 37

Summary


Overloading Insertion and Extraction Operators
Example 1
Example 2
Tips

Overloading Insertion and Extraction Operators

We are already aware that while overloading operators, functions are written and spirit or
behavior of the operators ( +, -, *, / ) is maintained in their implementations. Similarly
the operator’s spirit is kept intact while overloading stream insertion and extraction
operators.
We get an integer as input by writing the following lines:
int i;
cin >> i;

Have a look on the stream extraction operator’s ( >> ) behavior here. The similar
behavior is maintained when we overload this stream extraction operator ( >> ) or stream
insertion operator ( << ).
There are couple of important things to take care of, before starting implementation for
overloading an operator:
The first thing to see is the type of the operator i.e. whether the operator is binary or
unary. The binary operator takes two operands while unary operator takes one. The
number of operands for an operator cannot be changed while overloading it.
Page 471
Secondly, the programmer has to take care of, what an operator is returning back. For
example, in case of addition ( + ), it returns back the result of addition. So the cascading
statement like a + b + c; can be executed successfully. In this case, at first, b + c is
executed. The result of this operation is returned by the operator +, to add it in the
variable a. So in actual, the operation is carried out as:
a + ( b + c).

We want to overload stream extraction ( >> ) and insertion ( << ) operators which are
actually already overloaded. See the code lines below:
1. int i = 123;
2. double d = 456.12;
3. float f = 789.1;
4.
5. cout << i << “ “;
6. cout << d << “ “;
7. cout << f;
You can see the lines 5, 6 and 7. The same stream insertion operator ( << ) has been used
with different data types of int, double and float. Alternatively, these lines (5, 6 and 7)
can be written within statement of one line:
cout << i << “ “<< d << “ “<< f;

Similarly, the stream extraction operator ( >> ) is used with different data types in the
following manner:
cin >> i;
cin >> d;
cin >> f;

Here, stream extraction operator is used with different data types of int, double and float.
The three lines given above can be written in one cascading line:
cin >> i >> d >> f;

The file iostream.h contains the operator overloading declarations for these stream
insertion ( << ) and extraction ( >> ) operators for native data types. The declarations
inside this file look like the following:
Page 472
istream& operator>>(char*);
istream& operator>>(unsigned char* p) { return operator>>((char*)p); }
istream& operator>>(signed char*p) { return operator>>((char*)p); }
istream& operator>>(char& c);
istream& operator>>(unsigned char& c) {return operator>>((char&)c);}
istream& operator>>(signed char& c) {return operator>>((char&)c);}
istream& operator>>(int&);
istream& operator>>(long&);
#if defined(__GNUC__)
__extension__ istream& operator>>(long long&);
__extension__ istream& operator>>(unsigned long long&);
#endif
istream& operator>>(short&);
istream& operator>>(unsigned int&);
istream& operator>>(unsigned long&);
istream& operator>>(unsigned short&);
#if _G_HAVE_BOOL
istream& operator>>(bool&);
#endif
istream& operator>>(float&);
istream& operator>>(double&);
istream& operator>>(long double&);
istream& operator>>( __manip func) {(*func)(*this); return *this;}
istream& operator>>(__imanip func) { return (*func)(*this); }
istream& operator>>(streambuf*);
In order to use these insertion ( << ) and extraction ( >> ) operators with classes, we have
to overload these operators.
As discussed in the previous lectures, there are two ways of overloading operators, either
as class members or non-members. But these insertion ( << ) and extraction ( >> )
operators cannot be overloaded as members. The reason is obvious as the driving object
is on the left side of the operator for member operators. In case of stream insertion ( << )
and extraction operators ( >> ), the object on the left side is either cin or cout usually.
These cin and cout objects will remain intact for our overloaded insertion and extraction
operators. Therefore, the overloaded operators cannot be member operators. Now, we are
left with no option but to overload these operators as non-members. While overloading
these operators as non-members, either we can use setters and getters of the objects
(provided that they are present as part of the class interface) or declare the operator as the
friend
of the class to access the private members directly. Remember, we can only
declare friends of our classes and not those of classes e.g., we cannot declare a
function as a friend of istream or ostream class. Normally, when define a class (declare
functions as friends inside it), the friend functions are defined below the class’s
definition.
Page 473
Here we are going to declare our overloaded operators as friends of our classes. The
object on the left of the operator will be a stream object like cin, cout and on the right will
be the object of our class.
We should be clear about the return type of the overloaded operator as the operator
function has to support the cascading operations. In case of stream insertion operator ( <<
), the operator function returns a reference to the ostream to support cascading
operations. An example prototype of stream insertion operator ( << ) is as under:
ostream & operator << ( ostream & output, Vehicle v );
cout
object will be replaced with its reference output, therefore, in the definition of this
operator function, output will be used as cout. Note that the first parameter is passed by
reference and the compiler does not allow it to pass by value. The first object is returned
back by reference by the operator function. That’s why, the compiler does not allow to
pass first parameter by value. We must be remembering that the objects passed by value
are local to the function and destroyed when the function returns. Therefore, it does not
make sense to return references of the objects, passed by value to the function.
As we are declaring this operator function as friend of our class Vehicle, the private
members of Vehicle will be accessible to this operator function. For example, tyre is a
private
data member of type int inside Vehicle class and inside the operator function’s
implementation, we can access it by simply writing v.tyre as:
output << v.tyre;

The above statement actually is:
cout << v.tyre;
tyre
is of native data type int. The output will work for native data types as it is actually
cout
, which is overloaded for all native data type. We are constructing a building using
the basic building blocks. We can use the already used bricks to construct new walls.
Similarly, while writing out programs, we implement our overloaded operators using the
already available functionality of native data types.
Here is how we overload stream insertion operator ( << ) for our Date class:
#include <iostream.h>
class Date
{
friend ostream& operator << ( ostream & os, Date d );
// this non-member function is a friend of class date
. . .
. . .
};
ostream & operator << ( ostream & os, Date d )
{

Page 474
os << d.day << ”.” << d.month << ”.” << d.year; // access private data
// as friend
return os;
};

Likewise, we can overload stream extraction operator ( >> ). All the conditions for
overloading this operator are similar to that of stream insertion operator ( >>). It cannot
be a member operator, always a non-member operator function, declared as friend of the
class to be overloaded for. It returns an object of type istream &, accepts first parameter
of type istream &. There is one additional restriction on extraction operator ( >> ) i.e. the
second parameter is also passed by reference as that object is modified by this operator
function. For our Date class, it is declared as:
istream & operator >> ( istream & input, Date & d );

Note that second parameter can also be passed by reference for insertion operator ( << )
but that is not mandatory and may be used to gain performance. But in case of extraction
operator ( >> ), it is mandatory to have second parameter of reference type.
Example 1

Following is our
Date class containing the overloaded insertion (
<< ) and extraction ( >> ) operators:

/* Date class containing overloaded insertion and extraction operators. */
# include <iostream.h>
class Date
{
public:
Date( )
{
cout << "\n Parameterless constructor called ...";
month = day = year = 0;
}
~Date ( )
{
// cout << "\n Destructor called ...";
}
// Methods, not directly related to the example have been taken out from the class
Page 475
friend ostream & operator << ( ostream & os, Date d );
friend istream & operator >> ( istream & is, Date & d );
private:
int month, day, year;
};
ostream & operator << ( ostream & os, Date d )
{
os << d.day << "." << d.month << "." << d.year; // access private data of
//Date being a friend
return os;
};
istream & operator >> ( istream & is, Date& d )
{
cout << "\n\n Enter day of the date: ";
cin >> d.day;
cout << " Enter month of the date: ";
cin >> d.month;
cout << " Enter year of the date: ";
cin >> d.year;
return is;
};
main(void)
{
Date date1, date2;
cout << "\n\n Enter two dates";
cin >> date1 >> date2;
cout << "\n Entered date1 is: " << date1 << "\n Entered date2 is: " << date2;
}
The output of the program is:
Parameterless constructor called ...
Parameterless constructor called ...
Enter two dates: ...
Enter day of the date: 14
Enter month of the date: 12
Enter year of the date: 1970
Page 476
Enter day of the date: 05
Enter month of the date: 09
Enter year of the date: 2000
Entered date1 is: 14.12.1970
Entered date2 is: 5.9.2000
Example 2

Following is an example of a Matrix class, where until now, we have not overloaded
insertion ( << ) and extraction operators ( >> ).
/* Matrix class, which is without overloading stream operators */
#include <iostream.h>
#include <stdlib.h>
class Matrix
{
private :
int numRows, numCols ;
float elements [30] [30] ;
public :
Matrix( int rows , int cols ) ;
void getMatrix ( ) ;
void displayMatrix ( ) ;
};
Matrix :: Matrix ( int rows = 0 , int cols = 0)
{
numCols = cols ;
numRows = rows ;
for ( int i = 0 ; i < numRows ; i ++ )
{
for ( int j = 0 ; j < numCols ; j ++ )
{
elements [ i ] [ j ] = 0 ;
}
}
}
Page 477
void Matrix :: getMatrix ( )
{
for ( int i = 0 ; i < numRows ; i ++ )
{
for ( int j = 0 ; j < numCols ; j ++ )
{
cin >> elements [ i ] [ j ] ;
}
}
}
void Matrix :: displayMatrix ( )
{
for ( int i = 0 ; i < numRows ; i ++ )
{
cout << "| " ;
for ( int j = 0 ; j < numCols ; j ++ )
{
cout << elements [ i ] [ j ] << " " ;
}
cout << "|" << endl ;
}
}
void main ( )
{
Matrix matrix (2, 2) ;
matrix.getMatrix ( ) ;
matrix.displayMatrix ( ) ;
system ( "PAUSE" ) ;
}
The operator functions ( <<, >> ) are not overloaded for this program. A specific function
getMatrix()
has been called to get the values for the matrix object this entirely a different
way than we used to do for primitive data types. For example, we used to get int i as; cin
>> i. Similarly, we called a method displayMatrix() to display the values in the matrix
object. We can see here, if we overload insertion ( << ) and extraction ( >> ) operators
then the user of our class, does not need to know the specific names of the functions to
input and display our objects.
Page 478
The changed program after overloading insertion, extraction operators and few additional
statements to format the output properly:
/* Matrix class, with overloaded stream insertion and extraction operators. */
#include <iostream.h>
#include <stdlib.h>
class Matrix
{
float elements[30][30];
int numRows, numCols;
public:
Matrix ( int rows = 0 , int cols = 0 )
{
numRows = rows;
numCols = cols;
}
friend ostream & operator << ( ostream & , Matrix & );
friend istream & operator >> ( istream & , Matrix & );
};
istream & operator >> ( istream & input , Matrix & m )
{
for ( int i = 0; i < m.numRows; i ++ )
{
for ( int j = 0; j < m.numCols; j ++ )
{
input >> m.elements [ i ] [ j ] ;
}
}
return input;
}
ostream & operator << ( ostream & output , Matrix & m )
{
for ( int r = 0; r < m.numRows; r++ )
{
for ( int c = 0; c < m.numCols; c++ )
{
output << m.elements [ r ] [ c ] << ‘\t’ ;
}
output << endl;
}
return output ;
Page 479
}
int main ( )
{
Matrix matrix ( 3 ,3 );
cout << “\nEnter a 3 * 3 matrix \n\n“;
cin >> matrix ;
cout << “\nEntered matrix is: \n”;
cout << matrix;
system ( "PAUSE" );
return 0;
}
The output of the program is:
Enter a 3 * 3 matrix
45
65
34
23
72
135
90
78
45
Entered matrix is:
45 65 34
23 72 135
90 78 45
Press any key to continue . . .
You can see both the operators are declared friends of the Matrix class so that they can
directly access the private members of the Matrix.
The insertion operator ( << ) is accepting both the parameters left and right by reference.
We already know that for insertion operator ( << ), it is not really required to pass the
second parameter (the Matrix object in this case) by reference but we have used here to
gain efficiency. The function is returning an object ostream &, i.e., it is returning a
reference to a ostream object, that actually is the required in order to support cascaded
operations using this operator.
The extraction operator ( >> ) is also accepting both the parameters by reference. But for
this operator, it is mandatory to accept the Matrix object by reference because this
Page 480
function is modifying that object. Similar to the insertion operation, this function is also
returning a reference to istream object in order to support cascaded operations.
Clearly after overloading the operators << and >>, it is more convenient for the
programmer to use these already familiar operators to display and input the object data
members. Readability of the program has also comparatively increased.
Tips

Stream insertion ( << ) and extraction operators ( >> ) are always implemented as
non-member functions.
operator << returns a value of type ostream & and operator >> returns a value of type
istream & to support cascaded operations.
The first parameter to operator << is an ostream & object. cout is an example of an
ostream object. Similarly first parameter to operator >> is an istream & object. cin is
an example of an istream object. These first parameters are always passed by
reference. The compiler won't allow you to do otherwise.
For operator >>, the second parameter must also be passed by reference.
The second parameter to operator << is an object of the class that we are overloading
the operator for. Similar is the case for operator >>.

<Previous Lesson

Introduction to Programming

Next Lesson>

Home

Lesson Plan

Topics

Go to Top

Copyright © 2008-2013 zainbooks All Rights Reserved
Next Lesson
Previous Lesson
Lesson Plan
Topics
Home
Go to Top