<< & >> stream operator overloading

To read and write classes to and from streams (input / output), overloaded methods are required for the stream insertion << and stream extraction >> operators.

 

The << and >> are usually shit left and shift right bitwise operators that are overloaded in the ostream and istream classes of the iostream file, that is usually included at the beginning of a program with the following statement:    #include <iostream>

 

When used for output, the << operator is known as the insertion operator.

When used for input, the >> operator is known as the extraction operator.

 

These operators act as insertion / extraction operators when cout / cin is used on the left of the statement as the driving object for their relative implementations within the ostream or istream class of the iostream file.

 

Overloading << Output

cout is actually an object of the ostream class, which has function prototypes for the builtin data types such as int, float as follows:

 

ostream & operator<<(ostream&, int) ;

ostream & operator<<(ostream&, float) ;

 

As you can see they both return a reference to ostream, which is implemented in the function body by returning the next address for output to allow chained statements of the form: cout << objectA << objectB << objectC << endl ; The left operand should always be returned when we want overloaded binary operator to be chained.

 

They both also accept two parameters, those being a reference to ostream and the relevant data type.

 

Similarly, we can write our own overloaded << operator functions to act upon our classes.

 

A typical overloaded << function prototype would look like this:

 

friend ostream& operator<<(ostream&, const MyClass&) ;

 

The prototype is declared as a friend function to allow the function to access members of the class, and since it takes an ostream as its first parameter it can't be a member of the class.

 

The second parameter is defined as a const to ensure that the function does not alter the incoming object.

 

Because the function has to be defined as a friend and not a member function, the class name and scope resolution operator :: are not required. However, this necessitates the use of the class name and the dot operator for the relevant members required. This also means that the function cannot use the self referencing 'this' pointer, and cannot directly refer member data just by using their attribute name.

 

This example illustrates overloading the insertion stream operator >> to print the values of a class:

#include <string>
#include <iostream>
using namespace std;

class MyClass {
	private:
		int myVar ;
		float myFlt ;
		string myStr ;

	public:
		MyClass(int a = 6, float b = 6.6, string c = "Diablo") :
				myVar(a), 	myFlt(b), 		myStr(c) {}

	friend ostream& operator<<(ostream&, const MyClass&);
};

ostream& operator<<(ostream& abc, const MyClass& printClass){

	abc << "myVar: " << printClass.myVar << ", myFlt: " << \
			printClass.myFlt << ", myStr: " << printClass.myStr << endl ;
	return abc ;
}

int main() {

	MyClass david(9, 4.567, "David");

	cout << david ;

	MyClass noko ;

	cout << noko ;

	return 0 ;
}

Compile & Run:

myVar: 9, myFlt: 4.567, myStr: David
myVar: 6, myFlt: 6.6, myStr: Diablo

 


 

Overloading >> Input

 

The extraction operator >>  can also be overloaded for input, using the istream class of the iostream file, and has a similar prototype to the above:

 

friend istream& operator>>(istream&, MyClass&) ; 

 

Again the prototype is declared as a friend to allow access to  members of the class (in this case to set the values) and taking an istream as its first parameter means it can't be a member of the class.

 

Returning a reference allows chaining.

 

#include <string>
#include <iostream>
using namespace std;

class MyClass {
	private:
		int myVar ;
		float myFlt ;
		string myStr ;

	public:
		MyClass(int a = 6, float b = 6.6, string c = "Diablo") :
				myVar(a), 	myFlt(b), 		myStr(c) {}

	friend ostream& operator<<(ostream&, const MyClass&);

	friend istream& operator>>(istream&, MyClass&) ;
};

ostream& operator<<(ostream& abc, const MyClass& printClass){

	abc << "myVar: " << printClass.myVar << ", myFlt: " << \
			printClass.myFlt << ", myStr: " << printClass.myStr << endl ;
	return abc ;
}

istream& operator>>(istream& xyz, MyClass& getClass){
	cout << "please enter an int: " ;
	xyz >> getClass.myVar ;

	cout << "please enter a float: " ;
	xyz >> getClass.myFlt ;

	cout << "please enter a string: " ;
	xyz >> getClass.myStr ;

	return xyz ;
}

int main() {

	MyClass jimmy ;

	cin >> jimmy ;

	cout << jimmy ;

	return 0 ;
}
please enter an int: 5
please enter a float: 21.45
please enter a string: Jimmy
myVar: 5, myFlt: 21.45, myStr: Jimmy

Leave a Reply