Mastering C++ Operator Overloading: A Practical Tutorial

Posted by Anonymous and classified in Computers

Written on in English with a size of 5.41 KB

In C++, Operator Overloading is a compile-time polymorphism feature that allows you to grant custom meanings to existing C++ operators (like +, -, *, ==, etc.) when they are applied to user-defined data types (objects).

It does not let you create new operators (you cannot invent a ** operator), nor does it change the precedence or associativity of existing ones. It simply makes your custom objects behave intuitively, like built-in data types.

1. Syntax of Operator Overloading

To overload an operator, you define a special member function using the operator keyword followed by the symbol you want to overload.

ReturnType operator Symbol (Arguments) {
    // Custom logic here
}

2. Overloading Unary Operators

A unary operator operates on a single operand. Examples include the unary minus (-), increment (++), and decrement (--) operators.

When you overload a unary operator as a member function, it takes no arguments because it implicitly operates directly on the object that called it.

Example: Overloading the Unary Minus (-)

Let's change the sign of coordinates in a Space object.

#include <iostream>
using namespace std;

class Space {
private:
    int x, y, z;
public:
    Space(int a, int b, int c) : x(a), y(b), z(c) {}

    // Overloading the unary minus operator
    void operator-() {
        x = -x;
        y = -y;
        z = -z;
    }

    void display() {
        cout << "X: " << x << ", Y: " << y << ", Z: " << z << endl;
    }
};

int main() {
    Space s(10, -20, 30);
    cout << "Original: ";
    s.display();

    -s; // Activates custom operator-() function

    cout << "After Unary Minus: ";
    s.display(); 
    return 0;
}

3. Overloading Binary Operators

A binary operator operates on two operands (like +, -, ==, <, etc.).

When overloaded as a member function, the operator function accepts exactly one argument:

  • The object on the left side of the operator invokes the function.
  • The object on the right side of the operator is passed into the function as the argument.

Example: Overloading the Binary Plus (+)

Let's overload + to add two mathematical Complex numbers (a + bi).

#include <iostream>
using namespace std;

class Complex {
private:
    float real;
    float imag;
public:
    Complex(float r = 0, float i = 0) : real(r), imag(i) {}

    // Overloading binary '+'
    // 'other' represents the object on the right side of the '+'
    Complex operator+(const Complex &other) {
        Complex temp;
        temp.real = this->real + other.real;
        temp.imag = this->imag + other.imag;
        return temp;
    }

    void display() {
        cout << real << " + " << imag << "i" << endl;
    }
};

int main() {
    Complex c1(3.5, 2.5), c2(1.2, 4.3);
    Complex c3;

    c3 = c1 + c2; // Equivalent to: c3 = c1.operator+(c2);

    cout << "Result: ";
    c3.display();
    return 0;
}

4. Manipulation of Strings Using Operators

While standard library strings (std::string) already have overloaded operators, creating a custom MyString class demonstrates how operators like + (concatenation) and == (comparison) are implemented under the hood.

Example: Custom String Concatenation and Comparison

The code below overloads + to combine text and == to check if two custom strings are identical.

#include <iostream>
#include <cstring>
using namespace std;

class MyString {
private:
    char str[100];
public:
    MyString(const char s[] = "") {
        strcpy(str, s);
    }

    // Overloading '+' for string concatenation
    MyString operator+(const MyString &other) {
        MyString temp;
        strcpy(temp.str, this->str);
        strcat(temp.str, other.str); // Combine both arrays
        return temp;
    }

    // Overloading '==' for string comparison
    bool operator==(const MyString &other) {
        return (strcmp(this->str, other.str) == 0);
    }

    void display() {
        cout << str << endl;
    }
};

int main() {
    MyString s1("Hello, ");
    MyString s2("World!");
    MyString s3;

    // Concatenation using +
    s3 = s1 + s2; 
    cout << "Concatenated String: ";
    s3.display();

    // Comparison using ==
    MyString s4("Hello, World!");
    if (s3 == s4) {
        cout << "Strings match perfectly!" << endl;
    } else {
        cout << "Strings are different." << endl;
    }

    return 0;
}

Key Constraints of Operator Overloading

While highly versatile, you must keep these rules in mind:

  • Non-overloadable operators: The scope resolution operator (::), dot operator (.), pointer-to-member operator (.*), and ternary conditional operator (?:) cannot be overloaded.
  • No default arguments: You cannot specify default values for parameters in an operator function.
  • Maintain logical consistency: While you can technically make the + operator subtract numbers, doing so creates highly confusing code. Always respect the original intent of the symbol.

Related entries: