Operator overloading lets you reinterpret C++ operators in user-defined data types like classes and structs. By making custom types behave naturally like built-in types, this feature simplifies coding. An overloaded operator is a function with a unique name, both the operator symbol (e.g., operator+ or operator<<) and the keyword operator. Overloading most C++ operators doesn’t modify operand count, precedence, or associativity.
Input/Output Operators Overloading in C++
Bitwise shift operations in C++ are typically coupled to >> (extraction) and << (insertion) operators. However, the C++ Standard Library strongly overloads them for text, integer, and stream object I/O operations like std::cin and cout. Console data is read or printed using std::cout and cin.
Key Considerations for Overloading >> and <<
Non-Member Functions: According to the iostream library’s rules, IO operators have to be regular non-member functions. If they were member functions of your class, the left-hand operand would need to be an object of your class type (myDataObject \< cout; for example, which is not the standard method). You are unable to add members to std::istream and std::ostream since they are built into the standard library.
Friend Functions: In the class declaration, IO operators are frequently stated as friend functions since they typically need to access the private and protected data members of the class they are working on.
Parameters:
- The first parameter for operator\< (output/insertion) is often a reference to a non-const std::ostream object because streams cannot be cloned and writing to them modifies their state. Since printing an object normally doesn’t alter its type, the second parameter is usually a reference to the class type’s const.
- An input operator’s function is to modify the non-const object into which data will be read, hence the first parameter for operator>> (input/extraction) is a reference to std::istream, and the second parameter is a reference to the non-const object.
Return Type and Chaining: Both operator<< and operator>> return a reference to the stream object (std::ostream or std::istream). I/O operations can be chained or cascaded, e.g., std::cin >> obj1 >> obj2; or std::cout << obj1 << Management of Errors (for operator>>)
Error Handling (for operator>>): It is best practice for the input operator to verify if the input operations were successful (for example, if (is) or if (in)) and to put the object in a consistent state (for example, its default state) in the event of an error.
Example of Code: Overloading and for a Class
A user-defined Distance class that maintains measures in feet and inches can have its input (>>) and output (<<) operators overloaded, as seen in this example.
#include <iostream>
class Distance {
private:
int feet;
float inches;
public:
Distance() : feet(0), inches(0.0f) {}
Distance(int ft, float in) : feet(ft), inches(in) {}
friend std::ostream& operator<<(std::ostream& os, const Distance& d);
friend std::istream& operator>>(std::istream& is, Distance& d);
};
std::ostream& operator<<(std::ostream& os, const Distance& d) {
os << d.feet << "'-" << d.inches << "\"";
return os;
}
std::istream& operator>>(std::istream& is, Distance& d) {
int temp_feet;
float temp_inches;
char dash, quote;
is >> temp_feet >> dash >> temp_inches >> quote;
if (is && dash == '\'' && quote == '\"') {
d.feet = temp_feet;
d.inches = temp_inches;
} else {
is.setstate(std::ios::failbit);
d = Distance();
std::cerr << "Input format error for Distance. Expected: feet'-inches\"\n";
}
return is;
}
int main() {
Distance dist1(5, 6.5f), dist2;
std::cout << "Initial dist1: " << dist1 << "\n";
std::cout << "Initial dist2: " << dist2 << "\n";
std::cout << "\nEnter distance for dist2 (e.g., 10'-8\"): ";
std::cin >> dist2;
std::cout << "After input, dist2: " << dist2 << "\n";
Distance dist3(1, 1.0f);
std::cout << "\nChained output: dist1=" << dist1 << " dist2=" << dist2 << " dist3=" << dist3 << "\n";
std::cout << "\nAttempting invalid input for dist1 (e.g., 7.0m): ";
std::cin.clear();
std::cin.ignore(1000, '\n');
std::cin >> dist1;
std::cout << "After invalid input, dist1: " << dist1 << "\n";
if (std::cin.fail()) {
std::cout << "Input stream is in a failed state.\n";
}
return 0;
}
Output
Initial dist1: 5'-6.5"
Initial dist2: 0'-0"
Enter distance for dist2 (e.g., 10'-8"): 10'-8"
After input, dist2: 10'--8"
Chained output: dist1=5'-6.5" dist2=10'--8" dist3=1'-1"
Attempting invalid input for dist1 (e.g., 7.0m): 7.0m
Input format error for Distance. Expected: feet'-inches"
After invalid input, dist1: 0'-0"
Input stream is in a failed state.
You can also read Overloading Operators In C++: Practical Examples, Advantages