Overloading and Default Arguments
2 min read
Overloading and Default Arguments
C++ allows multiple functions with the same name and lets parameters have default values. Both features reduce the number of names you need to invent while keeping call sites readable.
Function overloading
Two functions are overloads of each other when they share a name but differ in parameter types or count. The compiler selects the best match at each call site:
#include <iostream>
#include <string>
void print(int n) { std::cout << "int: " << n << "\n"; }
void print(double d) { std::cout << "double: " << d << "\n"; }
void print(const std::string& s){ std::cout << "string: " << s << "\n"; }
int main() {
print(42); // int: 42
print(3.14); // double: 3.14
print("hello"); // string: hello
}
The compiler performs overload resolution: it builds a set of candidates, ranks them by how well the argument types match the parameter types, and calls the best one. If there is a tie or no valid candidate, it is a compile error.
Overloading pitfalls
Overloads are resolved at compile time using the static types of the arguments. Implicit conversions can cause surprises:
void f(int n) { std::cout << "int\n"; }
void f(long n) { std::cout << "long\n"; }
f(42); // int
f(42L); // long
f(42.0); // ambiguous: double converts equally well to int and long — compile error
When in doubt, add an explicit overload or use explicit casts at the call site.
Default arguments
A parameter with a default value can be omitted by the caller:
#include <iostream>
void draw_box(int width = 10, int height = 5, char fill = '*') {
for (int r = 0; r < height; r++) {
for (int c = 0; c < width; c++) std::cout << fill;
std::cout << "\n";
}
}
int main() {
draw_box(); // 10×5 box of *
draw_box(6); // 6×5 box of *
draw_box(4, 2); // 4×2 box of *
draw_box(3, 3, '#'); // 3×3 box of #
}
Default arguments must appear at the end of the parameter list. You cannot skip a parameter — to use fill you must also supply width and height.
Combining overloading and defaults
Overloading and default arguments solve similar problems. Prefer default arguments when the function body is identical across all variations; prefer overloading when the bodies differ:
// Good use of defaults — same logic, different defaults
std::string repeat(const std::string& s, int n = 1);
// Good use of overloading — different logic per type
int parse(const std::string& s);
int parse(const char* s);
int parse(std::string_view s);
Overloading on const
Member functions can be overloaded on const. The const version is called on const objects; the non-const version on mutable objects:
class Buffer {
std::string data;
public:
std::string& get() { return data; } // mutable access
const std::string& get() const { return data; } // read-only access
};
Learn modern C++ through working code. Each chapter introduces one concept — variables, functions, classes, templates, smart pointers, concurrency — with a clear example, a line-by-line explanation, and notes on how it applies in real programs.
View book →