Docs

README

Function Overloading in C++

Table of Contents

  1. Introduction
  2. How Overloading Works
  3. Overload Resolution
  4. Common Use Cases
  5. Ambiguity and Pitfalls
  6. Overloading vs Default Arguments
  7. Operator Overloading Preview
  8. Best Practices

Introduction

Function overloading allows multiple functions with the same name but different parameters. The compiler selects the correct version based on the arguments.

int add(int a, int b);           // For integers
double add(double a, double b);  // For doubles
string add(string a, string b);  // For strings

Why Overload?

  • Consistent interface for similar operations
  • Avoid inventing many function names (addInt, addDouble, addString)
  • Cleaner, more intuitive API

How Overloading Works

Function Signature

The signature determines uniqueness:

  • Function name
  • Number of parameters
  • Type of parameters
  • Order of parameters

NOT part of signature:

  • Return type
  • Parameter names
// Valid overloads - different signatures
void print(int x);
void print(double x);
void print(int x, int y);
void print(string s);

// INVALID - only differs by return type
int getValue();
double getValue();  // ERROR: redefinition

Name Mangling

The compiler internally renames functions to encode parameter types:

print(int)     → _Z5printi
print(double)  → _Z5printd
print(int,int) → _Z5printii

Overload Resolution

When you call an overloaded function, the compiler:

  1. Finds all candidates with that name
  2. Filters to viable functions (matching parameter count)
  3. Ranks by conversion quality
  4. Selects best match or reports ambiguity

Matching Priority (Best to Worst)

PriorityMatch TypeExample
1Exact matchprint(5)print(int)
2Promotionprint('a')print(int) (char→int)
3Standard conversionprint(3.14)print(int) (double→int)
4User-defined conversionCustom conversion operators

Examples

void func(int x);      // (1)
void func(double x);   // (2)
void func(long x);     // (3)

func(10);      // Exact → (1)
func(3.14);    // Exact → (2)
func(10L);     // Exact → (3)
func('A');     // Promotion char→int → (1)
func(10.0f);   // Promotion float→double → (2)

Common Use Cases

1. Different Types

void print(int value) {
    cout << "Integer: " << value << endl;
}

void print(double value) {
    cout << "Double: " << value << endl;
}

void print(const string& value) {
    cout << "String: " << value << endl;
}

2. Different Number of Arguments

int max(int a, int b) {
    return (a > b) ? a : b;
}

int max(int a, int b, int c) {
    return max(max(a, b), c);
}

int max(int a, int b, int c, int d) {
    return max(max(a, b), max(c, d));
}

3. Optional Parameters

void greet() {
    greet("World");  // Call other overload
}

void greet(const string& name) {
    greet(name, "Hello");
}

void greet(const string& name, const string& greeting) {
    cout << greeting << ", " << name << "!" << endl;
}

4. Container Variants

double average(const vector<int>& nums);
double average(const vector<double>& nums);
double average(const int* arr, size_t size);

Ambiguity and Pitfalls

Ambiguous Calls

void process(int x, double y);
void process(double x, int y);

process(1, 2);  // ERROR: ambiguous!
// Both require one conversion

// Fix: explicit cast
process(1, 2.0);  // Calls first
process(1.0, 2);  // Calls second

const Overloading

class Container {
public:
    int& get(int index);              // For non-const objects
    const int& get(int index) const;  // For const objects
};

Container c;
const Container cc;

c.get(0) = 10;   // Uses non-const version
int x = cc.get(0); // Uses const version

Reference vs Value Ambiguity

void func(int x);    // Value
void func(int& x);   // Reference

int n = 5;
func(n);  // ERROR: ambiguous!
func(5);  // OK: only value works (5 is rvalue)

Default Arguments Interaction

void display(int x, int y = 0);
void display(int x);

display(5);  // ERROR: ambiguous!

Overloading vs Default Arguments

AspectOverloadingDefault Arguments
Different logic✓ Each has own impl✗ Same impl
Compile-time bindingAt call siteAt call site
FlexibilityMore flexibleSimpler
Code duplicationMay duplicateSingle function

When to Use Each

Default Arguments:

// Same logic, just different defaults
void connect(string host, int port = 80, bool ssl = false) {
    // Single implementation
}

Overloading:

// Fundamentally different implementations
void sort(vector<int>& v) {
    // Integer-specific optimization
}

void sort(vector<string>& v) {
    // String comparison logic
}

Operator Overloading Preview

Operators are special functions that can be overloaded:

class Vector2D {
public:
    double x, y;

    Vector2D operator+(const Vector2D& other) const {
        return {x + other.x, y + other.y};
    }

    Vector2D operator*(double scalar) const {
        return {x * scalar, y * scalar};
    }

    bool operator==(const Vector2D& other) const {
        return x == other.x && y == other.y;
    }
};

Vector2D a{1, 2}, b{3, 4};
Vector2D c = a + b;      // Uses operator+
Vector2D d = a * 2.0;    // Uses operator*
bool eq = (a == b);      // Uses operator==

(Full coverage in 05_Operator_Overloading)


Best Practices

✅ Do

// Consistent behavior across overloads
int abs(int x);
double abs(double x);
long abs(long x);

// Clear semantic difference
void draw(Point p);
void draw(Line l);
void draw(Circle c);

❌ Don't

// Semantically different operations
void process(int x);      // Prints x
void process(string s);   // Writes to file
// Confusing - same name, completely different behavior!

// Too similar, easy to call wrong one
void update(int id, string name);
void update(string name, int id);

Guidelines Summary

  1. Overload for same conceptual operation on different types
  2. Avoid ambiguous parameter combinations
  3. Document when behavior differs between overloads
  4. Consider templates if logic is identical across types
  5. Be careful mixing overloading with default arguments

Quick Reference

// Valid overloads
void f(int);
void f(double);
void f(int, int);
void f(const string&);

// Invalid - return type doesn't distinguish
int f();
double f();  // ERROR

// const overloading (member functions)
T& get();
const T& get() const;

// Ambiguity resolution
void g(int, double);
void g(double, int);
g(1, 2);      // ERROR: ambiguous
g(1, 2.0);    // OK: first overload

Compile & Run

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