Operator Overloading in C++: A Comprehensive Guide
Chapter 14: Operator Overloading in C++
Chapter Objectives
After completing this chapter, you should be able to:
- Understand the concept of operator overloading.
 
The Need for Operator Overloading
Let’s revisit the clockType class from Chapter 11. Consider the following code snippet:
clockType noon(12, 0, 0);clockType classTime(11, 30, 0);noon.printTime();classTime.incrementSeconds();if (noon.equalTime(classTime)) {    cout << "The times are equal" << endl;}These statements work as intended, but C++ offers more intuitive ways to perform these operations. For instance, we typically use:
++to increment a value.==to compare two values for equality.
Operator overloading allows us to define how these standard C++ operators behave with objects of user-defined classes like clockType.
Understanding Operator Overloading
Many operators in C++ are already overloaded to work with various built-in data types. Take the output operator (<<) as an example. The following output statements are all valid:
cout << 10;cout << 3.14;cout << "Hello";cout << 'A';The compiler achieves this through operator functions. The keyword operator precedes the operator symbol to form the function name. Here are some examples:
| Operator | Function Name | 
|---|---|
<< | operator<< | 
++ | operator++ | 
== | operator== | 
+ | operator+ | 
Recall that overloading means having multiple functions with the same name. Since the output operator is overloaded, there are multiple operator<< functions. The compiler determines which function to call based on the parameter list. For example:
void operator<<(ostream&, int);void operator<<(ostream&, double);void operator<<(ostream&, const char*);void operator<<(ostream&, char);
When the compiler encounters an operator, it calls the corresponding function, passing the left and right operands as parameters.
cout << 10; // Calls function declaration 1cout << 3.14; // Calls function declaration 2cout << "Hello"; // Calls function declaration 3cout << 'A'; // Calls function declaration 4Restrictions on Operator Overloading
There are some limitations to operator overloading:
- You cannot alter the precedence of an operator.
 - The associativity (left-to-right or right-to-left evaluation) cannot be changed.
 - Default parameters are not allowed.
 - You cannot modify the number of parameters an operator accepts.
 - You cannot introduce new operators.
 - Certain operators cannot be overloaded: 
.,.*,::,?:,sizeof. - The fundamental meaning of an operator should be preserved (e.g., 
+should represent addition). 
Overloading Binary Operators as Non-Member Functions
Binary operators are typically overloaded as non-member functions, meaning they are not part of the class itself. We define them outside the class declaration.
Overloading the Output Operator (<<)
Let’s demonstrate this with the clockType class. We’ll overload the output operator to display the time in the format HH:MM:SS.
// clockTypeA.h#include <iostream>using namespace std;class clockType {public:    clockType();    clockType(int, int, int);    void setTime(int, int, int);    void getTime(int&, int&, int&);    void incrementSeconds();    void incrementMinutes();    void incrementHours();    bool equalTime(const clockType& otherClock) const;private:    int hr;    int min;    int sec;};ostream& operator<<(ostream&, const clockType&); // Non-member function declaration// clockTypeA.cpp#include <iostream>#include "clockTypeA.h"using namespace std;// ... (Other member function definitions)ostream& operator<<(ostream& out, const clockType& right) {    int h, m, s;    right.getTime(h, m, s);    if (h < 10) {        out << "0";    }    out << h << ":";    if (m < 10) {        out << "0";    }    out << m << ":";    if (s < 10) {        out << "0";    }    out << s;    return out; // Return the ostream object for concatenation}Overloading the Input Operator (>>)
Similarly, we can overload the input operator to allow users to enter the time directly.
// clockTypeB.h// ... (Previous code)istream& operator>>(istream&, clockType&); // Non-member function declaration// clockTypeB.cpp// ... (Previous code)istream& operator>>(istream& in, clockType& right) {    int h, m, s;    cout << "Enter the hours: ";    in >> h;    cout << "Enter the minutes: ";    in >> m;    cout << "Enter the seconds: ";    in >> s;    right.setTime(h, m, s);    return in; // Return the istream object for concatenation}Correct Return Type for Input/Output Operators
To enable concatenation of input and output operators (like cout << "The time is " << myClock << endl;), we need to return the corresponding stream object (ostream& for output and istream& for input) from the overloaded operator functions. This allows the stream object to be used in subsequent operations.
Overloading the Equality Operator (==)
We can replace the equalTime member function with an overloaded operator== to compare two clockType objects for equality.
// clockTypeD.h// ... (Previous code)bool operator==(const clockType&, const clockType&); // Non-member function declaration// clockTypeD.cpp// ... (Previous code)bool operator==(const clockType& left, const clockType& right) {    int lh, lm, ls, rh, rm, rs;    left.getTime(lh, lm, ls);    right.getTime(rh, rm, rs);    return (lh == rh && lm == rm && ls == rs);}Overloading the Increment Operator (++)
The increment operator (++) is a unary operator, meaning it operates on a single operand. We’ll overload it as a member function to increment the clockType object by one second. To handle both pre-increment (++clock1) and post-increment (clock1++), we’ll define two versions of the operator++ function. The post-increment version takes an integer parameter (typically unused) to differentiate it from the pre-increment version.
// clockTypeD.h// ... (Previous code)clockType operator++(); // Pre-increment declarationclockType operator++(int); // Post-increment declaration// clockTypeD.cpp// ... (Previous code)clockType clockType::operator++() {    incrementSeconds();    return *this;}clockType clockType::operator++(int x) {    clockType temp = *this;    incrementSeconds();    return temp;}In the post-increment version, we create a temporary copy of the object before incrementing it. This ensures that the original value is returned, as expected in post-increment operations.
By overloading these operators, we can make our clockType class more user-friendly and integrate seamlessly with standard C++ syntax.
