Docs

README

Operator Overloading in C++

Table of Contents

  1. Introduction
  2. Syntax
  3. Arithmetic Operators
  4. Comparison Operators
  5. Stream Operators
  6. Assignment Operator
  7. Subscript and Function Call
  8. Friend Functions
  9. Best Practices

Introduction

Operator overloading lets you define how operators work with your custom types.

Vector v1(1, 2), v2(3, 4);
Vector v3 = v1 + v2;  // Uses overloaded +

Overloadable Operators

Can OverloadCannot Overload
+ - * / %:: . .*
== != < > <= >=?: sizeof
<< >>typeid
= [] ()
++ --
new delete

Syntax

As Member Function

class Number {
    int value;
public:
    Number operator+(const Number& other) const {
        return Number(value + other.value);
    }
};

As Non-Member (Friend)

class Number {
    int value;
    friend Number operator+(const Number& a, const Number& b);
};

Number operator+(const Number& a, const Number& b) {
    return Number(a.value + b.value);
}

Arithmetic Operators

class Vector {
    double x, y;
public:
    Vector(double x = 0, double y = 0) : x(x), y(y) {}

    Vector operator+(const Vector& v) const { return Vector(x + v.x, y + v.y); }
    Vector operator-(const Vector& v) const { return Vector(x - v.x, y - v.y); }
    Vector operator*(double s) const { return Vector(x * s, y * s); }
    Vector operator/(double s) const { return Vector(x / s, y / s); }

    Vector operator-() const { return Vector(-x, -y); }  // Unary minus
};

Compound Assignment

Vector& operator+=(const Vector& v) {
    x += v.x; y += v.y;
    return *this;
}

Increment/Decrement

class Counter {
    int value;
public:
    Counter& operator++() { ++value; return *this; }      // Pre
    Counter operator++(int) { Counter t = *this; ++value; return t; }  // Post
};

Comparison Operators

class Date {
    int year, month, day;
public:
    bool operator==(const Date& d) const {
        return year == d.year && month == d.month && day == d.day;
    }
    bool operator!=(const Date& d) const { return !(*this == d); }
    bool operator<(const Date& d) const {
        if (year != d.year) return year < d.year;
        if (month != d.month) return month < d.month;
        return day < d.day;
    }
    bool operator>(const Date& d) const { return d < *this; }
    bool operator<=(const Date& d) const { return !(d < *this); }
    bool operator>=(const Date& d) const { return !(*this < d); }
};

C++20 Spaceship Operator

#include <compare>
class Date {
    auto operator<=>(const Date&) const = default;  // All comparisons!
};

Stream Operators

class Point {
    int x, y;
public:
    friend ostream& operator<<(ostream& os, const Point& p) {
        return os << "(" << p.x << ", " << p.y << ")";
    }

    friend istream& operator>>(istream& is, Point& p) {
        return is >> p.x >> p.y;
    }
};

// Usage
Point p(3, 4);
cout << p << endl;  // (3, 4)
cin >> p;           // Input: 5 6

Assignment Operator

Copy Assignment

class String {
    char* data;
    size_t len;
public:
    String& operator=(const String& other) {
        if (this != &other) {  // Self-assignment check
            delete[] data;
            len = other.len;
            data = new char[len + 1];
            strcpy(data, other.data);
        }
        return *this;
    }
};

Move Assignment (C++11)

String& operator=(String&& other) noexcept {
    if (this != &other) {
        delete[] data;
        data = other.data;
        len = other.len;
        other.data = nullptr;
        other.len = 0;
    }
    return *this;
}

Subscript and Function Call

Subscript []

class Array {
    int* data;
    size_t size;
public:
    int& operator[](size_t i) { return data[i]; }
    const int& operator[](size_t i) const { return data[i]; }
};

Function Call ()

class Adder {
    int value;
public:
    Adder(int v) : value(v) {}
    int operator()(int x) const { return x + value; }
};

Adder add5(5);
cout << add5(10);  // 15

Friend Functions

Use friend when left operand isn't your class:

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

    // 2.0 * complex needs friend
    friend Complex operator*(double d, const Complex& c) {
        return Complex(d * c.real, d * c.imag);
    }
};

Complex c(1, 2);
Complex r = 2.0 * c;  // Works!

Best Practices

✅ Do

// Return reference for compound assignment
T& operator+=(const T& other) { ...; return *this; }

// Implement in terms of compound
T operator+(const T& a, const T& b) { T t = a; return t += b; }

// Const correctness
bool operator==(const T& other) const;

// Self-assignment check
T& operator=(const T& other) {
    if (this != &other) { ... }
    return *this;
}

❌ Don't

// Don't change expected behavior
T operator+(const T& other) { /* don't subtract! */ }

// Don't overload &&, ||, or comma
T operator&&(const T& other);  // Breaks short-circuit

// Don't return references to temporaries
T& operator+(const T& other) { T t = ...; return t; }  // Dangling!

Quick Reference

class T {
public:
    // Arithmetic
    T operator+(const T& r) const;
    T& operator+=(const T& r);
    T operator-() const;          // Unary
    T& operator++();              // Pre
    T operator++(int);            // Post

    // Comparison
    bool operator==(const T& r) const;
    bool operator<(const T& r) const;

    // Assignment
    T& operator=(const T& r);
    T& operator=(T&& r) noexcept;

    // Subscript
    E& operator[](size_t i);

    // Function call
    R operator()(Args...);

    // Stream (friend)
    friend ostream& operator<<(ostream&, const T&);
    friend istream& operator>>(istream&, T&);
};

Compile & Run

g++ -std=c++17 -Wall examples.cpp -o examples && ./examples
README - C++ Tutorial | DeepML