ZeePedia

Overloading Insertion and Extraction Operators

<< Stream Manipulations, Manipulators, Non Parameterized Manipulators, Formatting Manipulation
User Defined Manipulator, Static keyword, Static Objects >>
img
CS201 ­ Introduction to Programming
Lecture Handout
Introduction to Programming
Lecture No. 37
Reading Material
Deitel & Deitel - C++ How to Program
Chapter 11
11.3, 11.3.1, 11.4, 11.4.1
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 470
img
CS201 ­ Introduction to Programming
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 471
img
CS201 ­ Introduction to Programming
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 library 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 472
img
CS201 ­ Introduction to Programming
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 473
img
CS201 ­ Introduction to Programming
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 474
img
CS201 ­ Introduction to Programming
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 475
img
CS201 ­ Introduction to Programming
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 476
img
CS201 ­ Introduction to Programming
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 477
img
CS201 ­ Introduction to Programming
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 478
img
CS201 ­ Introduction to Programming
}
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 479
img
CS201 ­ Introduction to Programming
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 >>.
Page 480
Table of Contents:
  1. What is programming
  2. System Software, Application Software, C language
  3. C language: Variables, Data Types, Arithmetic Operators, Precedence of Operators
  4. C++: Examples of Expressions, Use of Operators
  5. Flow Charting, if/else structure, Logical Operators
  6. Repetition Structure (Loop), Overflow Condition, Infinite Loop, Properties of While loop, Flow Chart
  7. Do-While Statement, for Statement, Increment/decrement Operators
  8. Switch Statement, Break Statement, Continue Statement, Rules for structured Programming/Flow Charting
  9. Functions in C: Structure of a Function, Declaration and Definition of a Function
  10. Header Files, Scope of Identifiers, Functions, Call by Value, Call by Reference
  11. Arrays: Initialization of Arrays, Copying Arrays, Linear Search
  12. Character Arrays: Arrays Comparisonm, Sorting Arrays Searching arrays, Functions arrays, Multidimensional Arrays
  13. Array Manipulation, Real World Problem and Design Recipe
  14. Pointers: Declaration of Pointers, Bubble Sort Example, Pointers and Call By Reference
  15. Introduction, Relationship between Pointers and Arrays, Pointer Expressions and Arithmetic, Pointers Comparison, Pointer, String and Arrays
  16. Multi-dimensional Arrays, Pointers to Pointers, Command-line Arguments
  17. String Handling, String Manipulation Functions, Character Handling Functions, String Conversion Functions
  18. Files: Text File Handling, Output File Handling
  19. Sequential Access Files, Random Access Files, Setting the Position in a File, seekg() and tellg() Functions
  20. Structures, Declaration of a Structure, Initializing Structures, Functions and structures, Arrays of structures, sizeof operator
  21. Bit Manipulation Operators, AND Operator, OR Operator, Exclusive OR Operator, NOT Operator Bit Flags Masking Unsigned Integers
  22. Bitwise Manipulation and Assignment Operator, Programming Constructs
  23. Pre-processor, include directive, define directive, Other Preprocessor Directives, Macros
  24. Dynamic Memory Allocation, calloc, malloc, realloc Function, Dangling Pointers
  25. History of C/C++, Structured Programming, Default Function Arguments
  26. Classes and Objects, Structure of a class, Constructor
  27. Classes And Objects, Types of Constructors, Utility Functions, Destructors
  28. Memory Allocation in C++, Operator and Classes, Structures, Function in C++,
  29. Declaration of Friend Functions, Friend Classes
  30. Difference Between References and Pointers, Dangling References
  31. Operator Overloading, Non-member Operator Functions
  32. Overloading Minus Operator, Operators with Date Class, Unary Operators
  33. Assignment Operator, Self Assignmentm, Pointer, Conversions
  34. Dynamic Arrays of Objects, Overloading new and delete Operators
  35. Source and Destination of streams, Formatted Input and Output, Buffered Input/Output
  36. Stream Manipulations, Manipulators, Non Parameterized Manipulators, Formatting Manipulation
  37. Overloading Insertion and Extraction Operators
  38. User Defined Manipulator, Static keyword, Static Objects
  39. Pointers, References, Call by Value, Call by Reference, Dynamic Memory Allocation
  40. Advantages of Objects as Class Members, Structures as Class Members
  41. Overloading Template Functions, Template Functions and Objects
  42. Class Templates and Nontype Parameters, Templates and Static Members
  43. Matrices, Design Recipe, Problem Analysis, Design Issues and Class Interface
  44. Matrix Constructor, Matrix Class, Utility Functions of Matrix, Input, Transpose Function
  45. Operator Functions: Assignment, Addition, Plus-equal, Overloaded Plus, Minus, Multiplication, Insertion and Extraction