Functions
A function packages up a chunk of work under a name, so you can run it from anywhere without retyping it. C++ functions look almost identical to C's, but add one thing C doesn't have: a safe way to let a function reach back and change a variable in its caller, without resorting to pointers.
Declaring and calling a function
A function's signature says what it's called, what it returns, and what it takes in. Here, square takes an int and returns an int:
#include <iostream> int square(int n) { return n * n; } int main() { std::cout << "5 squared is " << square(5) << std::endl; std::cout << "12 squared is " << square(12) << std::endl; return 0; }
5 squared is 25 12 squared is 144
Each call to square(n) runs the function body fresh with n set to whatever was passed in, and return hands the result back to wherever the call happened — here, straight into std::cout.
Pass-by-value vs. pass-by-reference
By default, C++ passes arguments by value, just like C: the function gets its own copy, and changes to it never touch the caller's variable. Adding an & to a parameter's type makes it a reference instead — an alias for the caller's actual variable, so changes inside the function are visible outside it:
#include <iostream> void tryToDouble(int n) { n = n * 2; } void doubleIt(int& n) { n = n * 2; } int main() { int a = 10; tryToDouble(a); std::cout << "After tryToDouble: " << a << std::endl; int b = 10; doubleIt(b); std::cout << "After doubleIt: " << b << std::endl; return 0; }
After tryToDouble: 10 After doubleIt: 20
tryToDouble(int n) only ever modifies its own private copy of a, so the caller's a is untouched. doubleIt(int& n) takes n as a reference, meaning n and b are two names for the exact same memory — modifying n modifies b directly, no pointers or &/* juggling required at the call site.
std::vector) on every call would be wasteful. For a value that's just being read and is cheap to copy — an int, a bool — plain pass-by-value is simpler and usually just as fast.Default arguments
A parameter can be given a default value, which lets callers leave it out entirely when the default is what they want:
#include <iostream> void greet(std::string name, std::string greeting = "Hello") { std::cout << greeting << ", " << name << "!" << std::endl; } int main() { greet("Maya"); greet("Sam", "Welcome back"); return 0; }
Hello, Maya! Welcome back, Sam!
The first call only supplies name, so greeting falls back to "Hello". The second call supplies both, overriding the default. Default arguments must come last in the parameter list — you can't have a defaulted parameter followed by a non-defaulted one.
Function overloading
Unlike C, C++ lets you declare several functions with the same name as long as their parameter lists differ — the compiler picks the right one based on the arguments you pass:
#include <iostream>
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int main() {
std::cout << add(2, 3) << std::endl;
std::cout << add(2.5, 3.1) << std::endl;
return 0;
}
5 5.6
Both functions are named add, but they take different parameter types, so add(2, 3) resolves to the int version and add(2.5, 3.1) resolves to the double version. Overload resolution happens entirely at compile time, based on the types of the arguments at each call site.