cpp

overloading

01_overloading.cpp⚙️
/**
 * ============================================================
 * C++ FUNCTION OVERLOADING
 * ============================================================
 * 
 * This file covers:
 * - Function overloading basics
 * - Overloading rules
 * - Ambiguity issues
 * - Best practices
 * 
 * Compile: g++ -std=c++17 -Wall 01_overloading.cpp -o overloading
 * Run: ./overloading
 * 
 * ============================================================
 */

#include <iostream>
#include <string>
#include <vector>

using namespace std;

// ============================================================
// FUNCTION OVERLOADING - SAME NAME, DIFFERENT PARAMETERS
// ============================================================

/*
 * Function overloading allows multiple functions with the same name
 * but different parameter lists. The compiler determines which
 * function to call based on the arguments provided.
 * 
 * What can differ:
 * - Number of parameters
 * - Types of parameters
 * - Order of parameters (if types differ)
 * 
 * What CANNOT differ (for overloading):
 * - Return type alone
 * - Parameter names
 */

// ============================================================
// OVERLOADED print() FUNCTIONS
// ============================================================

// Print integer
void print(int value) {
    cout << "int: " << value << endl;
}

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

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

// Print character
void print(char value) {
    cout << "char: " << value << endl;
}

// Print boolean
void print(bool value) {
    cout << "bool: " << (value ? "true" : "false") << endl;
}

// Print with a label
void print(const string& label, int value) {
    cout << label << ": " << value << endl;
}

// ============================================================
// OVERLOADED add() FUNCTIONS
// ============================================================

int add(int a, int b) {
    return a + b;
}

double add(double a, double b) {
    return a + b;
}

string add(const string& a, const string& b) {
    return a + b;
}

// Three parameters
int add(int a, int b, int c) {
    return a + b + c;
}

// ============================================================
// OVERLOADED max() FUNCTIONS
// ============================================================

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

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

int max(int a, int b, int c) {
    return max(max(a, b), c);  // Uses the two-parameter version
}

// ============================================================
// OVERLOADED area() FUNCTIONS
// ============================================================

// Area of square
double area(double side) {
    cout << "  (Square)" << endl;
    return side * side;
}

// Area of rectangle
double area(double length, double width) {
    cout << "  (Rectangle)" << endl;
    return length * width;
}

// Area of circle (using different parameter type)
double area(double radius, bool isCircle) {
    if (isCircle) {
        cout << "  (Circle)" << endl;
        return 3.14159 * radius * radius;
    }
    return area(radius);  // Fall back to square
}

// ============================================================
// MAIN FUNCTION
// ============================================================

int main() {
    cout << "============================================" << endl;
    cout << "     C++ FUNCTION OVERLOADING" << endl;
    cout << "============================================" << endl << endl;

    // ========================================================
    // PART 1: BASIC OVERLOADING
    // ========================================================
    
    cout << "--- PART 1: BASIC OVERLOADING ---" << endl << endl;
    
    // Compiler chooses the right function based on argument types
    print(42);            // Calls print(int)
    print(3.14);          // Calls print(double)
    print("Hello");       // Calls print(const string&)
    print('A');           // Calls print(char)
    print(true);          // Calls print(bool)
    
    cout << endl;

    // ========================================================
    // PART 2: DIFFERENT NUMBER OF PARAMETERS
    // ========================================================
    
    cout << "--- PART 2: DIFFERENT PARAMETER COUNT ---" << endl << endl;
    
    cout << "add(5, 3) = " << add(5, 3) << endl;
    cout << "add(5, 3, 2) = " << add(5, 3, 2) << endl;
    
    // With label
    print("Age", 25);     // Calls print(string, int)
    print("Score", 100);
    
    cout << endl;

    // ========================================================
    // PART 3: DIFFERENT PARAMETER TYPES
    // ========================================================
    
    cout << "--- PART 3: DIFFERENT PARAMETER TYPES ---" << endl << endl;
    
    cout << "add(5, 3) = " << add(5, 3) << endl;
    cout << "add(5.5, 3.3) = " << add(5.5, 3.3) << endl;
    cout << "add(\"Hello\", \"World\") = " << add("Hello", " World") << endl;
    
    cout << "\nmax(10, 20) = " << max(10, 20) << endl;
    cout << "max(3.14, 2.71) = " << max(3.14, 2.71) << endl;
    cout << "max(5, 10, 7) = " << max(5, 10, 7) << endl;
    
    cout << endl;

    // ========================================================
    // PART 4: PRACTICAL EXAMPLE - AREA CALCULATION
    // ========================================================
    
    cout << "--- PART 4: AREA CALCULATIONS ---" << endl << endl;
    
    cout << "Area of square (5): " << area(5.0) << endl;
    cout << "Area of rectangle (4x6): " << area(4.0, 6.0) << endl;
    cout << "Area of circle (r=3): " << area(3.0, true) << endl;
    
    cout << endl;

    // ========================================================
    // PART 5: TYPE CONVERSION AND RESOLUTION
    // ========================================================
    
    cout << "--- PART 5: TYPE CONVERSION ---" << endl << endl;
    
    // Implicit conversions can affect overload resolution
    print(10);      // Exact match: print(int)
    print(10.5);    // Exact match: print(double)
    print(10.5f);   // float → double conversion: print(double)
    
    // Be careful with implicit conversions!
    // print(10L);  // long - might be ambiguous depending on overloads
    
    // Character literals
    print('X');     // Exact match: print(char)
    print(65);      // Exact match: print(int), not char!
    
    cout << endl;

    // ========================================================
    // PART 6: RULES AND BEST PRACTICES
    // ========================================================
    
    cout << "--- PART 6: RULES AND BEST PRACTICES ---" << endl << endl;
    
    cout << "OVERLOADING RULES:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "✓ Can differ in number of parameters" << endl;
    cout << "✓ Can differ in parameter types" << endl;
    cout << "✓ Can differ in parameter order (if types differ)" << endl;
    cout << "✗ Cannot differ ONLY in return type" << endl;
    cout << "✗ Cannot differ ONLY in parameter names" << endl;
    
    cout << "\nBEST PRACTICES:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "• Keep overloaded functions semantically similar" << endl;
    cout << "• Avoid too many overloads (confusing)" << endl;
    cout << "• Be cautious with implicit conversions" << endl;
    cout << "• Consider templates for type-generic functions" << endl;
    cout << "• Document overloaded functions clearly" << endl;
    
    cout << endl;

    // ========================================================
    // PART 7: WHAT DOESN'T WORK
    // ========================================================
    
    cout << "--- PART 7: COMMON MISTAKES ---" << endl << endl;
    
    cout << "The following would NOT compile:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "// Different return type only - ERROR!" << endl;
    cout << "// int getValue() { return 1; }" << endl;
    cout << "// double getValue() { return 1.0; }" << endl;
    cout << endl;
    cout << "// Different parameter names only - ERROR!" << endl;
    cout << "// void func(int x) { }" << endl;
    cout << "// void func(int y) { }  // Same as above!" << endl;
    cout << endl;
    cout << "// Default arguments can cause ambiguity" << endl;
    cout << "// void func(int x, int y = 0) { }" << endl;
    cout << "// void func(int x) { }  // Ambiguous call: func(5)" << endl;
    
    cout << endl;

    cout << "============================================" << endl;
    cout << "FUNCTION OVERLOADING SUMMARY:" << endl;
    cout << "============================================" << endl;
    cout << "• Same name, different parameters" << endl;
    cout << "• Compiler picks best match at compile time" << endl;
    cout << "• Return type alone doesn't distinguish" << endl;
    cout << "• Be careful with implicit type conversions" << endl;
    cout << "• Use for related operations on different types" << endl;
    cout << "============================================" << endl;

    return 0;
}

// ============================================================
// EXERCISES:
// ============================================================
/*
 * 1. Create overloaded functions to calculate the average of:
 *    - Two integers
 *    - Three integers
 *    - A vector of integers
 * 
 * 2. Create overloaded functions to find minimum:
 *    - Of two values (int, double, string versions)
 *    - Of three values
 *    - Of an array
 * 
 * 3. Create overloaded display() functions that:
 *    - Display an integer with optional label
 *    - Display a vector with optional separator
 *    - Display a 2D array with formatting
 * 
 * 4. Create overloaded concatenate() functions for:
 *    - Two strings
 *    - String and integer
 *    - String and double (with precision parameter)
 */
Overloading - C++ Tutorial | DeepML