Overloading stream insertion operators in C++
Stream operator overloading lets us redefine the input (>>) and output (<<) operators for user-defined classes. This lets custom objects interact with cin and cout like built-in types, making input/output intuitive and readable.
- By default, << and >> work only with built-in types. Overloading enables their use with user-defined objects.
- Supports chaining multiple input/output operations in one statement.
#include <iostream>
using namespace std;
class Complex
{
private:
int real, imag;
public:
Complex(int r = 0, int i = 0) : real(r), imag(i)
{
}
// Overload << and >> as friend functions
friend ostream &operator<<(ostream &out, const Complex &c);
friend istream &operator>>(istream &in, Complex &c);
};
// Overload << for output
ostream &operator<<(ostream &out, const Complex &c)
{
out << c.real << " + i" << c.imag;
return out;
}
// Overload >> for input
istream &operator>>(istream &in, Complex &c)
{
in >> c.real >> c.imag;
return in;
}
int main()
{
Complex c1;
cout << "Enter real and imaginary parts: ";
cin >> c1;
cout << "The complex number is: " << c1 << endl;
return 0;
}
Output
Enter real and imaginary parts: The complex number is: 0 + i0
Explanation: This program overloads the >> and << operators to allow easy input and output of Complex objects. It uses friend functions to access private members and format input/output like built-in types.
Rules for Stream Operators Overloading
When overloading stream operators, the following rules must be followed:
- Always return the stream (ostream& or istream&) by reference to allow chaining of multiple input/output operations.
- Pass both the stream and the object by reference to avoid unnecessary copying.
- Declare the parameter as const in the insertion operator (<<) since output operations do not modify the object.
- Implement the operator as a non-member function, but declare it as a friend if access to private members is required.
Why these operators must be overloaded as global?
In operator overloading, if an operator is overloaded as a member, then it must be a member of the object on the left side of the operator. For example, consider the statement "ob1 + ob2" (let ob1 and ob2 be objects of two different classes). To make this statement compile, we must overload '+' in a class of 'ob1' or make '+' a global function.
The operators '<<' and '>>' are called like 'cout << ob1' and 'cin >> ob1'. So if we want to make them a member method, then they must be made members of ostream and istream classes, which is not a good option most of the time. Therefore, these operators are overloaded as global functions with two parameters, cout and object of user-defined class.