Overloading and Default Arguments
C++ lets several functions share one name as long as their parameters differ — overloading — and lets parameters have default values. Both make functions easier to call without inventing names like print_int and print_double.
Function overloading
#include <iostream> #include <string> #include <vector> void show(int value) { std::cout << "int: " << value << '\n'; } void show(double value) { std::cout << "double: " << value << '\n'; } void show(const std::string& value) { std::cout << "string: \"" << value << "\"\n"; } void show(const std::vector<int>& v) { std::cout << "vector of " << v.size() << " ints\n"; } int main() { show(42); show(3.5); show(std::string{"hello"}); show(std::vector<int>{1, 2, 3}); }
int: 42 double: 3.5 string: "hello" vector of 3 ints
The compiler picks the overload whose parameters best match the arguments. Overloads must differ in their parameter types or count — a different return type alone isn't enough.
Ambiguity
When two overloads match equally well, the call is ambiguous and won't compile:
void scale(float factor) {} void scale(long factor) {} int main() { scale(2); // int converts equally well to float or long }
main.cpp:5:5: error: call to 'scale' is ambiguous
Fix it by passing an argument of the exact type (2L, 2.0f) or by adding an int overload. Keep overload sets small and obviously related.
Default arguments
Parameters can have default values, used when the caller leaves them out. Defaults must come at the end of the parameter list:
#include <iostream> #include <string> void greet(const std::string& name, const std::string& greeting = "Hello", int times = 1) { for (int i = 0; i < times; ++i) { std::cout << greeting << ", " << name << "!\n"; } } int main() { greet("Ada"); greet("Grace", "Welcome"); greet("Linus", "Hi", 2); }
Hello, Ada! Welcome, Grace! Hi, Linus! Hi, Linus!
Put the default in the declaration (usually in a header) only — not repeated in the definition.
Overloading vs. defaults vs. templates
- Default arguments — when the function does the same thing and some inputs usually have the same value.
- Overloads — when different input types need genuinely different code.
- Templates (lesson 39) — when the same code works for many types.
#include <iostream> template <typename T> T largest(T a, T b) { return a > b ? a : b; } int main() { std::cout << largest(3, 9) << ' ' << largest(2.5, 1.5) << ' ' << largest('a', 'z') << '\n'; }
9 2.5 z
inline functions
Short functions defined in headers are often marked inline. In modern C++ this doesn't mainly mean "insert the code at the call site" (the optimiser decides that on its own); it means the definition may appear in several source files without breaking the one-definition rule (lesson 48).
Try it yourself
Write circle_area for a circle, then two overloads of area: one for a rectangle (width, height) and one taking a single int for a square.
circle r=2: 12.5664 rect 3x4: 12 square 5: 25