C++ Functions

Functions & Lambdas

Functions, overloading, and the crucial choice C++ forces on you that managed languages hide: pass by value or by reference.

C++20 3 Topics
01

Functions & Overloading

C++ functions declare a return type and typed parameters. Overloading allows many functions with one name but different parameter lists, and default arguments let callers omit trailing parameters.

C++ — Overloading & Defaults
// returnType name(params) { body }
int add(int a, int b) { return a + b; }

// Overloading — same name, different parameter types
double add(double a, double b) { return a + b; }

// Default arguments — greet() or greet("Hi")
void greet(std::string msg = "Hello") {
    std::cout << msg;
}
greet();            // "Hello"
greet("Hi there");  // "Hi there"

// Declare before use, or provide a forward declaration:
int square(int n);   // prototype — defined later
Default arguments go in the declaration, not the definition, and only trailing parameters may have them. Unlike Python, they're evaluated per call, so a default like vector<int>() is fresh each time.
02

Pass by Value vs Reference

This is the choice that defines C++ performance. By value copies the argument. By reference (&) passes an alias, so no copy is made and the function can modify the original.

C++ — The Three Passing Styles
// by value — copies, caller's variable unchanged
void byValue(int x) { x = 99; }

// by reference — no copy, MODIFIES the caller's variable
void byRef(int& x) { x = 99; }

// by const reference — no copy, cannot modify (the default for big objects)
void byConstRef(const std::vector<int>& v) {
    std::cout << v.size();   // reads, never copies
}

int n = 5;
byValue(n);   std::cout << n;   // 5 — unchanged
byRef(n);     std::cout << n;   // 99 — modified
Rule of thumb: pass small types (int, double) by value; pass big objects (vector, string, classes) by const T&; use non-const T& only when you deliberately want to mutate the caller's object.
03

Lambdas

A lambda (C++11) is an anonymous function you can define inline and pass to STL algorithms. The [] capture list controls which surrounding variables it can access.

C++ — Lambdas & Captures
#include <algorithm>

// [capture](params) { body }
auto square = [](int x) { return x * x; };
square(5);        // 25

// capture by value [=] or by reference [&]
int factor = 3;
auto scale = [factor](int x) { return x * factor; };   // copies factor
scale(10);       // 30

// pass a lambda to an STL algorithm
std::vector<int> nums = {1, 2, 3, 4, 5};
int evens = std::count_if(nums.begin(), nums.end(),
    [](int x) { return x % 2 == 0; });   // 2

// sort by a custom comparator
std::sort(nums.begin(), nums.end(),
    [](int a, int b) { return a > b; });   // descending
Capturing by reference [&] is a dangling-reference trap: if the lambda outlives the captured variable (stored and called later), it references freed memory. Capture by value [=] when the lambda may escape the current scope.

Quick Quiz

1. Passing by value does what to the argument?
2. Big objects should typically be passed as…
3. Overloaded functions must differ in…
4. In a lambda, [&] captures surrounding variables…
5. Default arguments may be given to…