Bytebook Compiler

From C to C++

Functions: Overloading, Defaults & Inline

What C++ adds to functions: pass by reference, const references, function overloading, default arguments and inline functions.

4 min read5 runnable examples4-question quiz

Pass by reference

A reference parameter lets a function change the caller's variable — without pointers:

C++
#include <iostream>
using namespace std;

void swapValues(int &a, int &b) {     // a and b are aliases for the caller's variables
    int t = a;
    a = b;
    b = t;
}

int main() {
    int x = 3, y = 8;
    swapValues(x, y);                 // no & needed at the call
    cout << "x = " << x << ", y = " << y << endl;
    return 0;
}
Output
x = 8, y = 3

Compare the three ways of passing an argument:

By value By pointer (C style) By reference
Declaration void f(int a) void f(int *a) void f(int &a)
Call f(x) f(&x) f(x)
Can change caller's variable no yes yes
Copies the argument yes no (copies an address) no

const references

Passing a large object (like a long string or vector) by value copies the whole thing. Pass it as a const reference instead: no copy, and the function promises not to change it.

C++
#include <iostream>
#include <string>
using namespace std;

int countVowels(const string &s) {      // fast and read-only
    int n = 0;
    for (char c : s)
        if (string("aeiouAEIOU").find(c) != string::npos) n++;
    return n;
}

int main() {
    string text = "Object Oriented Programming";
    cout << countVowels(text) << " vowels" << endl;
    return 0;
}
Output
9 vowels

Function overloading

Several functions can share a name if their parameter lists differ (in number or types). The compiler picks the right one from the arguments — this is compile-time polymorphism.

C++
#include <iostream>
using namespace std;

int area(int side)                 { return side * side; }               // square
int area(int length, int width)    { return length * width; }            // rectangle
double area(double radius)         { return 3.14159 * radius * radius; } // circle

int main() {
    cout << "square 4:      " << area(4) << endl;
    cout << "rectangle 4x6: " << area(4, 6) << endl;
    cout << "circle 2.0:    " << area(2.0) << endl;
    return 0;
}
Output
square 4:      16
rectangle 4x6: 24
circle 2.0:    12.5664

Default arguments

Parameters can have default values, used when the caller leaves them out. Defaults must come last in the parameter list:

C++
#include <iostream>
using namespace std;

double simpleInterest(double principal, double rate = 7.5, int years = 1) {
    return principal * rate * years / 100;
}

int main() {
    cout << simpleInterest(10000) << endl;          // rate 7.5, 1 year
    cout << simpleInterest(10000, 8) << endl;       // 1 year
    cout << simpleInterest(10000, 8, 3) << endl;
    return 0;
}
Output
750
800
2400

Inline functions

inline suggests that the compiler paste the function body at each call, avoiding call overhead for tiny functions. It is a safer replacement for function-like macros because arguments are evaluated once and type-checked:

C++
#include <iostream>
using namespace std;

inline int cube(int x) { return x * x * x; }
#define CUBE(x) x * x * x

int main() {
    cout << "inline cube(1 + 2) = " << cube(1 + 2) << endl;    // 27
    cout << "macro  CUBE(1 + 2) = " << CUBE(1 + 2) << endl;    // 1 + 2*1 + 2*1 + 2 = 7
    return 0;
}
Output
inline cube(1 + 2) = 27
macro  CUBE(1 + 2) = 7

Modern compilers decide on inlining by themselves, so inline is mostly a hint (and today it matters mainly for functions defined in headers).

Test yourself

4 questions · pick an answer to check it instantly

  1. 1

    Which declaration lets f change the caller's int without pointers?

  2. 2

    Which pair is a valid overload?

  3. 3

    Which default-argument declaration is valid?

  4. 4

    Why pass a large string as const string &?