Operator Overloading in C++

Operator-Overloading-in-C-Feature-Image.jpg

Operator overloading in C++ is done by programmers to redefine the standard operators without changing their original meaning, which enhances code reusability, readability, and efficiency. Also, it helps in performing operations on complex numbers and custom memory management.

In this operator overloading tutorial, we will discuss operator overloading in C++, types of overloading in C++, the difference between function overloading and operator overloading, rules and idioms for the operator overloading, operators that can be overloaded and that cannot be, binary and unary operator overloading, advantages and disadvantages of operator overloading, and important points to remember about the operator overloading in C++.

Table of Contents:

What is Operator Overloading in C++

Operator overloading in C++ is a basic feature that helps programmers define custom behavior for the C++ operators when they are used with user-defined data types such as classes and structures. It helps the programmers by enabling objects to be manipulated by using the standard C++ operators just as the built-in data types.

Why Use Operator Overloading in C++?

Below are a few reasons why operator overloading in C++ can be used:

  • Operator overloading in C++ improves performance, code readability, and usability.
  • It allows custom data types to behave like the built-in data types in C++.
  • It also helps to simplify the complex expressions with the user-defined objects.

Syntax of Operator Overloading in C++

return_type ClassName::operator op (parameter_list) {
// Operator overloading implementation
}

Example:

Cpp

Output:

Syntax of Operator Overloading in C++ Output

The code shows the operator overloading in C++, as the + operator is redefined to add two Complex objects by using the overloaded operator + function. This is a common example that shows how to overload operators in C++.

Types of Overloading in C++

Types of Overloading in C++

There are two types of overloading in C++:

  1. Function Overloading
  2. Operator Overloading

Function Overloading in C++

Function overloading in C++ allows multiple functions to have the same name but different parameters, and the compiler determines which function should be called based on the number and types of arguments.

Example:

Cpp

Output:

Function Overloading in C++ Output

The code shows the function overloading in C++, as in the code, there are multiple add functions with the same name but different parameters, and the compiler will select the function that will be passed to the function calls based on the number and types of arguments.

Note: We have already discussed operator overloading in C++ above, so please refer to that.

Difference Between Function Overloading and Operator Overloading in C++

Feature Function Overloading Operator Overloading
Definition Defining multiple functions with the same name but different parameter lists. Redefining the behavior of C++ operators (+, -, *, etc.) for user-defined types.
Purpose Improves code readability by using the same function name for different tasks. Allows C++ operators to work with objects of custom classes.
Usage Used to perform different operations using the same function name but with different arguments. Used to perform operations on user-defined types (objects) using standard operators.
Syntax int add(int a, int b);
double add(double a, double b);
Complex operator+(const Complex &c);
Implementation Implemented by defining multiple functions with the same name but different parameter lists. Implemented by defining an operator function inside or outside the class.
Return Type The return type does not differentiate overloaded functions. The return type can be different depending on the operator.
Works on Only on functions. Both unary (++, –, !) and binary (+, -, *, /, ==) operators.
Friend Function Usage Not required. Can use friend functions for non-member overloading.

Can All Operators Be Overloaded in C++?

No, all operators cannot be overloaded in C++, but we can also say that almost all operators can be overloaded; only a few cannot be overloaded.

Operators That Cannot Be Overloaded in C++

Below is a list of C++ operators that cannot be overloaded:

Operator Description
:: (Scope Resolution) Accesses namespaces and class members.
. (Member Access) Directly accesses object members.
.* (Pointer-to-Member) Used with pointers to class members.
?: (Ternary Operator) Conditional (if-else) operator.
sizeof Returns the size of a type or variable.
typeid Used for runtime type identification.
alignof Determines memory alignment requirements.
co_await Used in coroutines for asynchronous programming.

Operators That Can Be Overloaded in C++

Below is a list of operators that can be overloaded in C++:

Category of Operators Operators
Arithmetic Operators +, -, *, /, %
Relational (Comparison) Operators ==, !=, <, >, <=, >=
Logical Operators &&
Bitwise Operators &
Assignment Operators =, +=, -=, *=, /=, %=, &=, |
Increment and Decrement Operators ++, —
Subscript Operator []
Function Call Operator ()
Pointer Operators * (dereference), -> (member access)
Stream Insertion and Extraction Operators <<, >>

Why Can’t Certain Operators Be Overloaded in C++?

Below are the reasons why the operators cannot be overloaded in C++:

1. [::] (Scope Resolution) – Scope resolution is used to access the namespace and class members, and redefining it will break the basic C++ syntax.

2. [ . ](Member Access) – It directly accesses the object members, and overloading it would interfere with the member access rules.

3. [.* ](Pointer-to-Member) – It is used to access the class members through the pointers, and if you try to change it, then it disrupts the behavior of the pointer.

4. [?:] (Ternary Operator) – The ternary operator is used for the complex evaluation order, and overloading it would change the conditional expressions.

5. sizeof – The sizeof operator in C++ is used to determine the size of the object, which is evaluated at compile time. So, it cannot be changed to work at runtime.

6. typeid – It is used for runtime type identification (RTTI), and thus, overloading it would break the built-in type checking.

Rules and Idioms for Operator Overloading in C++

To make sure that there is clear and maintainable operator overloading in C++, the basic rules and idioms must be followed. These are the operator’s precedence and associativity, or the number of operands, which cannot be changed and can only be overloaded by existing operators. Understanding these C++ operator overloading rules is crucial for anyone learning how to overload operators in C++.

Binary Operator Overloading in C++

Binary Operator Overloading in C++

Binary operator overloading in C++ allows user-defined classes to redefine the behavior of the binary operators when they are used with the objects. Also, a binary operator operates on two operands, which makes it different from a unary operator.

A binary operator in C++ can be overloaded in two ways:

1. It can be overloaded as a member function when the left operand is an object of the class. This is a common approach for binary operator overloading in C++.

Example:

Cpp

Output:

member function Output

The code shows how the binary operator * is overloaded as a member function to perform the matrix multiplication on the Matrix objects, which computes the product of two 2*2 matrices and prints the result to the console.

2. It can be overloaded as a friend function (non-member function) when the left operand is not an object of the class. This provides flexibility for binary operator overloading in C++.

Example:

Cpp

Output:

as a friend function Output

The code shows how the binary operator + is overloaded using a friend function in the C++ program to add two Complex numbers and print the result to the console. This example shows a common way of overloading + operator in C++.

Member vs. Non-member Operator Overloads

Aspect Member Function Non-Member Function
Where it’s written Inside the class Outside the class
Number of inputs One (right-side value) Two (left and right-side values)
Left-side object Must be the class object Can be any type (e.g., int + MyClass)
Access to private data Yes Only if it’s a friend function
Good for When the left side is always a class object When the left side might be something else
Example MyClass::operator+(MyClass b) operator+(MyClass a, MyClass b)
Common Use Simple operations where class is on the left Mixed-type operations or symmetry (a + b = b + a)

Unary Operator Overloading in C++

Overloading Unary Operators in C++

Unary operator overloading in C++ allows the user to change the behavior of a single operand operator for user-defined data types. A unary operator in C++ can be overloaded using the member functions since it works on a single object.

Example:

Cpp

Output:

Unary operator overloading in C++ Output

The code shows how the unary operator (-) is overloaded in C++ to negate the value of a Number object, which returns a new object with the negated value, and then the values are printed to the console.

Advanced Operator Overloading: [], (), ->, new/delete

Below are a few operators that can be overloaded, other than the relational and arithmetic operators:

1. Overloading the [ ] (Subscript Operator)

The subscript operator in C++ is overloaded to provide custom behavior as an array, and it must be implemented as a member function. This is a specialized form or method of C++ operator overloading.

Example:

Cpp

Output:

Overloading the [ ] (Subscript Operator) Output

The code shows how the subscript operator is overloaded to provide the custom behavior as an array to access the elements and changes with the bound checking.

2. Overloading the () (Function Call Operator)

Overloading the function call operator allows objects to be used as a function in a C++ program.

Example:

Cpp

Output:

Overloading the () (Function Call Operator) Output

The code shows how the function call ( ) operator is overloaded to allow the Multiplier object to be used as a function to multiply two numbers, 5 and 4, and then the result is printed to the console.

3. Overloading the -> (Arrow Operator)

The arrow operator in C++ is overloaded to return a pointer to an object for a smart pointer. This is crucial for custom pointer-like behavior in C++ operator overloading.

Example:

Cpp

Output:

Overloading the (Arrow Operator) Output

The code shows how the arrow -> operator is overloaded to allow a SmartPointer object to access the Test class functions, such as the raw pointer.

4. Overloading new and delete Operators

The new and delete operators in C++ are overloaded globally for debugging, logging, and customized memory management.

Example:

Cpp

Output:

Overloading new and delete Operators Output

The code shows how the new and delete operators are overloaded in a C++ program to display custom messages when there is dynamic memory allocation and deallocation.

Advantages of Operator Overloading in C++

  • The operator overloading in C++ improves the code readability by allowing operators to work with user-defined data types. 
  • It provides custom object behavior, which helps in operations such as matrix multiplication and complex number addition.
  • It improves the code reusability as the overloaded operators can be reused in different classes and reduces redundant function calls.
  • Operator overloading in C++ supports user-defined data types and maintains consistency with the built-in types. 
  • It is also important to enable the smart pointers for custom memory management through operator overloading in C++.

Disadvantages of Operator Overloading in C++

  • Overloading multiple C++ operators increases the code complexity because the code becomes harder to read and maintain.
  • The overloaded operators that have function calls give a slight performance overhead.
  • If the overloading is not done properly, then the overloaded operators will behave unexpectedly.
  • All operators cannot be overloaded; thus, it limits the customization of operators.
  • It is very difficult to find the errors in the overloaded operators as they work implicitly in the expressions.

Operator Overloading Use-Cases

Here are various operator overloading use-cases, showcasing how to overload operators in C++ for practical scenarios:

1. Arithmetic Operations
Overload operators like +, -, *, and / to perform arithmetic operations on objects.
Example: Complex + Complex, Vector * scalar

2. Comparison Operations
You can overload the relational operators such as ==, !=, <, >, etc., to compare objects.
Example: Comparing two dates, strings, or custom types

3. Assignment Operations
Overload the assignment operator = to define custom copy behavior, especially for deep copying dynamic memory.
Example: obj1 = obj2

4. Input/Output Operations
Overload the << and >> operators for easy and intuitive stream input/output.
Example: cout << obj, cin >> obj

5. Subscript Operator []
Useful in custom container classes to access elements using index notation.
Example: myArray[i]

6. Function Call Operator ()
Allows objects to be called like functions, useful for functors or callable classes.
Example: obj(args)

7. Increment/Decrement Operators (++, –)
Add custom behavior to increase or decrease object values.
Example: ++counter, value–

8. Dereference and Pointer-like Behavior
Overload * and -> to mimic pointer behavior, especially in smart pointer classes.
Example: ptr->method(), *ptr

Key Takeaways & Best Practices for Operator Overloading in C++

Here are some key C++ operator overloading rules and best practices:

  • You can only overload the already existing C++ operators.
  • You cannot change the operator’s precedence and associativity by overloading it. This is a fundamental C++ operator overloading rule.
  • All operators cannot be overloaded.
  • The overloaded operators have at least one operand that must be a user-defined type.
  • Operators can be overloaded as member and non-member functions.
  • Also, you cannot overload the operators for the standard data types such as int, float, etc.
  • The operators = and & are by default overloaded in C++.

Common Pitfalls in Operator Overloading

  1. Failing to overload both operand sequences, such as allowing (MyClass + int) but not (int + MyClass).
  2. Avoiding to mark as const to parameters or functions, which can lead to unexpected changes.
  3. Returning references to local variables can cause undefined behavior and should be avoided.
  4. Giving an operator an unexpected meaning, like taking + and making it subtraction. 
  5. Not handling self-assignment in your assignment operator (operator=).
  6. Forgetting to make non-member functions as friend functions when the function needs access to private members, especially for binary operator overloading in C++.
  7. Overloading one comparison operator (ie, ==) without overloading its related operators (eg,!=). 
  8. Overloading operators in C++ when the overload does not improve readability or makes the code more difficult to read.

Conclusion

The operator overloading in C++ helps in enhancing code readability, usability, and maintainability by allowing user-defined data types to behave as built-in data types. Also, it helps to simplify the various operations and must not be used unnecessarily. So, by understanding operator overloading with its advantages and disadvantages, you can easily overload the operators in C++ without any confusion or error. This operator overloading tutorial aims to provide you with a comprehensive understanding of how to overload operators in C++.

FAQs on Operator Overloading in C++

Q1. What is operator overloading in C++?

The operator overloading is redefining the standard operators for the user-defined types.

Q2. Why is operator overloading useful?

It improves code readability and usability by enabling intuitive operations on objects.

Q3. Can all C++ operators be overloaded?

No, the operators such as ::, ., .*, sizeof, typeid, and ?: cannot be overloaded.

Q4. What are the types of overloading in C++?

There are two types of overloading in C++: function overloading and operator overloading.

Q5. What are the key rules for operator overloading?

The rules for operator overloading are that at least one operand must be a user-defined type, and operator precedence cannot be changed.

Q6. What is the difference between operator and function overloading?

Operator overloading redefines how operators work with user-defined types, while function overloading allows multiple functions with the same name but different parameters.

Q7. Does operator overloading affect performance in C++?

Yes, operator overloading can affect performance if not used carefully, but it’s usually negligible when implemented efficiently.

Q8. When should you avoid operator overloading?

You should avoid operator overloading when it makes code less readable or breaks expected operator behavior.

About the Author

Technical Research Analyst - Full Stack Development

Kislay is a Technical Research Analyst and Full Stack Developer with expertise in crafting Mobile applications from inception to deployment. Proficient in Android development, IOS development, HTML, CSS, JavaScript, React, Angular, MySQL, and MongoDB, he’s committed to enhancing user experiences through intuitive websites and advanced mobile applications.

Full Stack Developer Course Banner