Functions: Overloading, Default Args, Inline

ফাংশন — ওভারলোডিং, ডিফল্ট আর্গুমেন্ট

Read: ~30 min 14 practice problems

1. Anatomy of a Function

add.cpp
#include <iostream>

// return-type   name   (parameters)
int add(int a, int b) {
    return a + b;
}

int main() {
    std::cout << add(3, 4) << "\n";
}

2. Function Overloading

Same name, different parameter types — the compiler picks the right one.

overload.cpp
#include <iostream>
#include <string>

int     add(int a, int b)         { return a + b; }
double  add(double a, double b)   { return a + b; }
std::string add(std::string a, std::string b) { return a + b; }

int main() {
    std::cout << add(2, 3) << "\n";
    std::cout << add(2.5, 3.5) << "\n";
    std::cout << add(std::string{"hi "}, std::string{"world"}) << "\n";
}
Cannot overload by return type alone int f(); and double f(); conflict — the call site doesn't say which to pick.

3. Default Arguments

default.cpp
#include <iostream>

int power(int base, int exp = 2) {
    int r = 1;
    for (int i = 0; i < exp; ++i) r *= base;
    return r;
}

int main() {
    std::cout << power(5) << "\n";       // 25 (uses default exp=2)
    std::cout << power(2, 10) << "\n";   // 1024
}
Rule Defaults must be from right to left: f(int a, int b = 0) ✓, f(int a = 0, int b) ✗.

4. inline & constexpr Functions

inline hints to the compiler to substitute the function body at the call site (skipping the call overhead). constexpr functions can be evaluated at compile time:

constexpr.cpp
#include <iostream>
#include <array>

constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

int main() {
    constexpr int f5 = factorial(5); // computed at compile time
    std::array<int, factorial(4)> arr; // size = 24, known at compile time
    std::cout << f5 << " " << arr.size() << "\n";
}

5. Trailing Return Type & auto Returns

trailing.cpp
// Trailing return type (C++11)
auto divide(int a, int b) -> double {
    return static_cast<double>(a) / b;
}

// Auto return-type deduction (C++14)
auto multiply(int a, int b) {
    return a * b; // deduced to int
}

6. Function Design Rules

  • One job: a function should do one thing well.
  • Small: if it doesn't fit on a screen, it's probably too big.
  • Pure when possible: same input → same output, no side effects.
  • Name describes behavior: computeAverage, not doStuff.
  • Fewer parameters: if you have 6+, group them into a struct.

7. Practice Problems

  1. Write int max(int a, int b).
    ✨ Show Answer
    int max(int a, int b) { return a > b ? a : b; }
  2. Overload area: one for circle (radius), one for rectangle (w, h).
    ✨ Show Answer
    double area(double r) { return 3.14159 * r * r; }
    double area(double w, double h) { return w * h; }
  3. Why can't you overload by return type only?
    ✨ Show Answer

    Overload resolution uses argument types only. The return type isn't visible at the call site (e.g. f(); alone doesn't say which return type you want).

  4. Write greet(std::string name = "World").
    ✨ Show Answer
    void greet(std::string name = "World") {
        std::cout << "Hello, " << name << "!\n";
    }
    // greet(); → "Hello, World!"
  5. What does constexpr on a function mean?
    ✨ Show Answer

    The function can be evaluated at compile time when called with constant arguments. If called with runtime values, it runs at runtime.

  6. Write a recursive constexpr fib(int n).
    ✨ Show Answer
    constexpr int fib(int n) {
        return n < 2 ? n : fib(n-1) + fib(n-2);
    }
  7. Write a function that returns nothing (void) and prints "Hi".
    ✨ Show Answer
    void sayHi() { std::cout << "Hi\n"; }
  8. Why is inline mostly redundant in modern C++?
    ✨ Show Answer

    Modern compilers inline aggressively based on profitability — inline is just a hint. Its remaining real purpose: allow multiple definitions across translation units (header-defined functions).

  9. Write a function with two default args.
    ✨ Show Answer
    int f(int a, int b = 1, int c = 2) { return a + b + c; }
  10. Write min overloaded for int, double, and string.
    ✨ Show Answer
    int min(int a, int b) { return a < b ? a : b; }
    double min(double a, double b) { return a < b ? a : b; }
    std::string min(std::string a, std::string b) { return a < b ? a : b; }

    (Better: use a function template — see Module 25.)

  11. What's a "pure" function?
    ✨ Show Answer

    A function that (1) always returns the same output for the same input and (2) has no side effects (no I/O, no global state mutation). Pure functions are easy to test and reason about.

  12. Show that add(2, 2) at compile-time gives 4 with constexpr.
    ✨ Show Answer
    constexpr int add(int a, int b) { return a + b; }
    static_assert(add(2, 2) == 4);

    static_assert fails to compile if expression isn't true.

  13. Forward declare foo at top, define at bottom.
    ✨ Show Answer
    void foo(); // declaration
    int main() { foo(); }
    void foo() { std::cout << "hi\n"; } // definition
  14. Why is C++ pass-by-value (default)?
    ✨ Show Answer

    To prevent surprise mutations from inside the called function. The function gets its own copy. To pass without copying, use const T&; to allow mutation, use T&.

Summary

Functions are the unit of abstraction. C++ allows overloading by argument types, default arguments (right-to-left), and constexpr functions for compile-time evaluation. Keep functions small, pure when possible, and well-named.

Next Module → References & Pass-by-value vs Pass-by-reference.