Operator Overloading

Operator overloading is a powerful feature in C++ that allows you to redefine the behavior of existing operators for your user-defined data types (classes and structures). This means you can make operators like +, -, *, ==, and others work seamlessly with your custom objects, mimicking how they work with built-in data types. This enhances code readability, maintainability, and makes your classes more intuitive to use.

Why Use Operator Overloading?

  • Readability: Code that uses overloaded operators often resembles mathematical expressions or familiar operations, making it easier to understand.
  • Maintainability: Overloading operators promotes consistent behavior for your custom types, simplifying future modifications.
  • Intuitive Use: Well-overloaded operators make your classes behave more naturally with other data types, improving user experience.

Understanding Operator Functions

Operator overloading is achieved by defining special member functions within your class called operator functions. These functions have a specific syntax that includes the operator keyword followed by the overloaded operator.

				
					returnType operator@ (const argumentType& other) {
    // Function body defining the behavior of the overloaded operator
}

				
			
  • returnType: The data type returned by the operator function.
  • operator@: The overloaded operator (e.g., +-==).
  • argumentType: The data type of the argument(s) the operator function takes. This can vary depending on the operator.
  • other: A reference to the second operand (if applicable) for binary operators.

Invalid Syntax

Operator overloading can not be performed directly on objects we have to define the behaviour like in the below code objects are created and adding them, but compiler generates an error. Here concept of overloading comes in picture.

				
					#include <iostream>
using namespace std;

class Add {
    int x;
};
 
int main()
{
    Add a1, a2, a3;
    a3 = a1 + a2;
    return 0;
}
				
			

Basic Operator Overloading

Lets take an example below is the description of code.

Complex Class Definition

  • The Complex class represents a complex number with two private data members: real (for the real part) and imag (for the imaginary part).
  • It has a constructor that initializes the real and imaginary parts of the complex number. If no arguments are provided, it defaults to (0, 0).

Operator Overloading

  • The class overloads four operators: +, -, *, and ==.
  • operator+: Adds two Complex objects and returns the result.
  • operator-: Subtracts one Complex object from another and returns the result.
  • operator*: Multiplies two Complex objects using the complex number multiplication formula and returns the result.
  • operator==: Checks if two Complex objects are equal by comparing their real and imaginary parts.

Main Function

  • Inside the main() function, two Complex objects c1 and c2 are created with initial values (10, 5) and (2, 4) respectively.
  • The overloaded +, -, *, and == operators are used to perform addition, subtraction, multiplication, and equality comparison between c1 and c2.
  • The results of these operations are stored in c3, c4, c5, and the result of the equality comparison is printed.
				
					#include <iostream>
using namespace std;

class Complex {
private:
    int real, imag;

public:
    Complex(int r = 0, int i = 0) {
        real = r;
        imag = i;
    }

    // Overloaded '+' operator to add two Complex objects
    Complex operator+(Complex const& obj) {
        Complex res;
        res.real = real + obj.real;
        res.imag = imag + obj.imag;
        return res;
    }

    // Overloaded '-' operator to subtract two Complex objects
    Complex operator-(Complex const& obj) {
        Complex res;
        res.real = real - obj.real;
        res.imag = imag - obj.imag;
        return res;
    }

    // Overloaded '*' operator to multiply two Complex objects
    Complex operator*(Complex const& obj) {
        Complex res;
        res.real = real * obj.real - imag * obj.imag;
        res.imag = real * obj.imag + imag * obj.real;
        return res;
    }

    // Overloaded '==' operator to check equality of two Complex objects
    bool operator==(Complex const& obj) {
        return (real == obj.real && imag == obj.imag);
    }

    // Utility function to print the Complex number
    void print() { cout << real << " + i" << imag << '\n'; }
};

int main() {
    Complex c1(10, 5), c2(2, 4);
    
    // Adding two Complex objects using the overloaded '+' operator
    Complex c3 = c1 + c2;
    cout << "Addition: ";
    c3.print();

    // Subtracting two Complex objects using the overloaded '-' operator
    Complex c4 = c1 - c2;
    cout << "Subtraction: ";
    c4.print();

    // Multiplying two Complex objects using the overloaded '*' operator
    Complex c5 = c1 * c2;
    cout << "Multiplication: ";
    c5.print();

    // Checking equality of two Complex objects using the overloaded '==' operator
    if (c1 == c2) {
        cout << "c1 and c2 are equal" << endl;
    } else {
        cout << "c1 and c2 are not equal" << endl;
    }

    return 0;
}

				
			
				
					// output //
Addition: 12 + i9
Subtraction: 8 + i1
Multiplication: 2 + i50
c1 and c2 are not equal

				
			

Explanation:

Addition

  • The Complex object c3 is the result of adding c1 and c2 using the overloaded + operator.
  • c1 has real part 10 and imaginary part 5, and c2 has real part 2 and imaginary part 4.
  • After addition, c3 has a real part of 12 (10 + 2) and an imaginary part of 9 (5 + 4).
  • So, the result of the addition is 12 + i9

Subtraction

  • The Complex object c4 is the result of subtracting c2 from c1 using the overloaded - operator.
  • c1 has real part 10 and imaginary part 5, and c2 has real part 2 and imaginary part 4.
  • After subtraction, c4 has a real part of 8 (10 – 2) and an imaginary part of 1 (5 – 4).
  • So, the result of the subtraction is 8 + i1.

Multiplication

  • The Complex object c5 is the result of multiplying c1 and c2 using the overloaded * operator.
  • c1 has real part 10 and imaginary part 5, and c2 has real part 2 and imaginary part 4.
  • After multiplication, c5 has a real part of 2 (102 – 54) and an imaginary part of 50 (104 + 52).
  • So, the result of the multiplication is 2 + i50.

Equality Comparison

  • We compare c1 and c2 for equality using the overloaded == operator.
  • Since c1 has different real and imaginary parts compared to c2, they are not equal.
  • Therefore, the output states that “c1 and c2 are not equal”.

Operators can not overloaded ?

  1. Scope Resolution Operator (::): It is used to define the scope of functions, variables, or classes. It cannot be overloaded because it is a compiler directive rather than an operator that operates on operands.

  2. Member Selection Operator (.*): It is used to access members of objects through pointers to members. It cannot be overloaded because it is tightly coupled with pointers to members.

  3. Conditional Operator (?:): It is a ternary operator used for conditional expressions. It cannot be overloaded because it has a fixed syntax and semantics defined by the language.

  4. Sizeof Operator (sizeof): It is used to determine the size of objects and data types. It cannot be overloaded because it operates at compile-time and does not require runtime polymorphism.

  5. typeid Operator (typeid): It is used to obtain the type information of an expression. It cannot be overloaded because it is a compile-time operator and its behavior is well-defined by the language.

  6. Increment (++) and Decrement (–) Operators: These operators can be overloaded as member functions, but their semantics cannot be changed. They must still perform increment or decrement operations on the object they are applied to.

  7. Comma Operator (,): It is used to separate expressions and evaluate them from left to right. It cannot be overloaded because its behavior is well-defined by the language and it does not operate on user-defined types.

Operators can be overloaded

Arithmetic Operators

  • Addition (+)
  • Subtraction (-)
  • Multiplication (*)
  • Division (/)
  • Modulus (%)

Assignment Operators

  • Assignment (=)
  • Addition and Assignment (+=)
  • Subtraction and Assignment (-=)
  • Multiplication and Assignment (*=)
  • Division and Assignment (/=)
  • Modulus and Assignment (%=)
  • Bitwise AND and Assignment (&=)
  • Bitwise OR and Assignment (|=)
  • Bitwise XOR and Assignment (^=)
  • Left Shift and Assignment (<<=)
  • Right Shift and Assignment (>>=)

Comparison Operators

  • Equality (==)
  • Inequality (!=)
  • Less than (<)
  • Greater than (>)
  • Less than or equal to (<=)
  • Greater than or equal to (>=)

Logical Operators

  • Logical NOT (!)
  • Logical AND (&&)
  • Logical OR (||)

Bitwise Operators

  • Bitwise NOT (~)
  • Bitwise AND (&)
  • Bitwise OR (|)
  • Bitwise XOR (^)
  • Left Shift (<<)
  • Right Shift (>>)

Increment and Decrement Operators

  • Prefix Increment (++)
  • Prefix Decrement (–)
  • Postfix Increment (++)
  • Postfix Decrement (–)

Member Access Operators

  • Member Access (->)
  • Member Access through Pointer (*)

Function Call Operator

  • Function call operator ()

Subscript Operator

  • Subscript operator ([])

Type Conversion Operators

  • Cast operator (Type())

Stream Operators

  • Insertion Operator (<<)
  • Extraction Operator (>>)

Operator overloading is a powerful feature of C++ that allows you to redefine the behavior of operators for user-defined types. By understanding the basics and advanced concepts of operator overloading, you can write more expressive and intuitive code. Remember to follow best practices and guidelines to ensure clarity and maintainability of your code.Happy coding !❤️

Table of Contents