Skip to content

Functions

Functions are the fundamental units of code organization in C++. They allow you to break down complex tasks into smaller, reusable pieces.

Declaration and Definition

  • Declaration (Prototype): Tells the compiler about the function's name, return type, and parameters. Usually in header files (.h).
  • Definition: The actual implementation of the function. Usually in source files (.cpp).
1
2
3
4
5
6
7
// Declaration
int add(int a, int b);

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

Parameter Passing

How you pass data to functions matters for performance and safety.

1. Pass by Value

Creates a copy of the argument. Safe, but slow for large objects.

1
2
3
void print_int(int x) { // x is a copy
    x = 10; // Does not affect the caller's variable
}

2. Pass by Reference (&)

Passes the original object. Fast (no copy), but allows modification.

1
2
3
void increment(int& x) {
    x++; // Modifies the caller's variable
}

3. Pass by Const Reference (const &)

The best of both worlds: fast (no copy) and safe (read-only). Use this for strings, vectors, and custom classes.

1
2
3
4
void print_message(const std::string& msg) {
    // msg = "New"; // Error: Read-only
    std::cout << msg;
}

Passing Arrays (std::span) (C++20)

Historically, arrays were passed as a pointer and a size. This is unsafe. C++20 introduces std::span, a lightweight view into an array.

#include <span>
#include <vector>

// Accepts raw arrays, std::vector, std::array
void print_data(std::span<const int> data) {
    for (int x : data) {
        std::cout << x << " ";
    }
}

std::vector<int> v = {1, 2, 3};
print_data(v); // OK

Discarded Return Values ([[nodiscard]])

If a function returns a value that should not be ignored (like an error code), mark it with [[nodiscard]]. The compiler will warn if the caller ignores it.

1
2
3
4
5
6
[[nodiscard]] bool connect() {
    // ... return true if successful
    return true;
}

// connect(); // Warning: ignoring return value

Function Overloading

You can have multiple functions with the same name, as long as their parameter lists differ.

1
2
3
void log(int value) { std::cout << "Int: " << value; }
void log(double value) { std::cout << "Double: " << value; }
void log(const std::string& msg) { std::cout << "String: " << msg; }

Default Arguments

You can provide default values for parameters. They must be at the end of the parameter list.

1
2
3
4
5
6
void connect(const std::string& ip, int port = 80) {
    // ...
}

connect("192.168.1.1");      // Uses port 80
connect("192.168.1.1", 443); // Uses port 443

inline Functions

The inline keyword suggests to the compiler to replace the function call with the function body itself. This can improve performance for small functions but increases binary size.

1
2
3
inline int max(int a, int b) {
    return (a > b) ? a : b;
}

constexpr Functions

These functions can be evaluated at compile-time if given constant arguments. This is powerful for performance.

constexpr int square(int x) {
    return x * x;
}

// Evaluated at compile-time!
constexpr int result = square(10); 
static_assert(result == 100);

// Evaluated at runtime
int input;
std::cin >> input;
int runtime_result = square(input); 

Return Type Deduction (auto) (C++14)

The compiler can deduce the return type from the return statement.

1
2
3
auto add(int a, int b) {
    return a + b; // Deduced as int
}