Functions — Definition, Overloading, Recursion
Function Declaration, Definition & Return Types
A C++ function has a return type (what kind of value it hands back), a name, a list of typed parameters, and a body. If a function doesn't return anything, its return type is void.
// add.cpp #include <iostream> int add(int a, int b) { return a + b; } int main() { int result = add(3, 4); std::cout << "3 + 4 = " << result << std::endl; return 0; }
int add(int a, int b) — the return type (int) comes first, then the name (add), then each parameter with its own type (int a, int b). C++ checks all of this at compile time: calling add("hi", "there") would fail to compile, because strings aren't ints.Pass by Value vs. Pass by Reference
By default, C++ passes arguments by value — the function receives a copy of the argument, so changes inside the function don't affect the caller's original variable. Adding an ampersand & to a parameter's type makes it a reference parameter — the function then operates on the caller's actual variable, and changes stick.
// pass_demo.cpp #include <iostream> void addOneByValue(int n) { n = n + 1; // only changes the local copy } void addOneByReference(int& n) { n = n + 1; // changes the caller's actual variable } int main() { int x = 10; addOneByValue(x); std::cout << "After addOneByValue: " << x << std::endl; // still 10 addOneByReference(x); std::cout << "After addOneByReference: " << x << std::endl; // now 11 return 0; }
std::string or a container) every time you call a function — which matters for performance. You'll often see const std::string& as a parameter type: a reference for efficiency, with const to promise the function won't modify it.Default Parameter Values
A parameter can have a default value, used automatically when the caller doesn't supply one. This lets you offer a simpler call signature for the common case while still allowing full control when needed.
// price.cpp #include <iostream> double calculatePrice(double base, double taxRate = 0.05) { return base + (base * taxRate); } int main() { std::cout << calculatePrice(100) << std::endl; // uses default 0.05 -> 105 std::cout << calculatePrice(100, 0.10) << std::endl; // overrides default -> 110 return 0; }
double calculatePrice(double taxRate = 0.05, double base) would not compile — base has no default and comes after one that does.Function Overloading
C++ lets you define multiple functions with the same name, as long as their parameter lists differ (in number or type of parameters). The compiler picks the right one based on the arguments you pass. This is called overloading — and it's a feature Python doesn't have, since Python resolves function names dynamically at call time rather than matching parameter types at compile time.
// overload.cpp #include <iostream> int multiply(int a, int b) { return a * b; } double multiply(double a, double b) { return a * b; } int multiply(int a, int b, int c) { return a * b * c; } int main() { std::cout << multiply(2, 3) << std::endl; // calls the (int,int) version -> 6 std::cout << multiply(2.5, 4.0) << std::endl; // calls the (double,double) version -> 10 std::cout << multiply(2, 3, 4) << std::endl; // calls the (int,int,int) version -> 24 return 0; }
Recursion
A recursive function calls itself to solve a smaller version of the same problem. Every correct recursive function needs a base case — a condition where it stops calling itself and returns directly — otherwise it recurses forever (and eventually crashes with a stack overflow).
// factorial.cpp #include <iostream> int factorial(int n) { if (n <= 1) { // base case: stop recursing return 1; } return n * factorial(n - 1); // recursive case: smaller subproblem } int main() { std::cout << "5! = " << factorial(5) << std::endl; // 120 return 0; }
5 * factorial(4) — but first it needs the result of factorial(4).factorial never checked n <= 1, it would call itself with smaller and smaller n forever — through 0, then negative numbers with no end — consuming stack memory on every call until the program crashes with a stack overflow.Lesson Summary
Let's recap everything you learned in this lesson:
&) lets the function modify the caller's original variable.Now it's your turn to write real code. Compile and run it with g++ or an online compiler.
Write a program called
sum_digits.cpp with a function int sumDigits(int n) that adds up the individual digits of a number. You can implement it either recursively (using n % 10 and n / 10, with a base case for n == 0) or iteratively with a loop. Call it from main() and print the result for 12345:
Rules: The function must take an
int and return an int. Print the result using std::cout in main().
💡 Show hints if you're stuck
- Recursive base case:
if (n == 0) return 0; - Recursive step:
return (n % 10) + sumDigits(n / 10); - Iterative version: loop
while (n > 0), addn % 10to a running total, then don /= 10; - 12345 → 1 + 2 + 3 + 4 + 5 = 15