← Back to C++ Course | Chapter 5: Functions | Lesson 7 of 13

C++ Function Overloading

Overloading by Parameter Type

C++ allows several functions to share the exact same name as long as their parameter types differ, so void print(int x) and void print(double x) can coexist — the compiler picks the right one automatically based on the argument type you pass at the call site. This is called function overloading.

Example: Overloading by Parameter Type

cpp
#include <iostream>

void print(int x) { std::cout << "int: " << x << std::endl; }
void print(double x) { std::cout << "double: " << x << std::endl; }

int main() {
	print(5);
	print(5.5);
	return 0;
}

Overloading by Number of Parameters

Functions can also be overloaded by how many parameters they take, so void log(string msg) and void log(string msg, string level) can both exist under the same name — the compiler distinguishes them purely by counting the arguments supplied at each call.

Example: Overloading by Number of Parameters

cpp
#include <iostream>
#include <string>

void log(std::string msg) { std::cout << msg << std::endl; }
void log(std::string msg, std::string level) { std::cout << "[" << level << "] " << msg << std::endl; }

int main() {
	log("Started");
	log("Started", "INFO");
	return 0;
}

Overloading by Order of Parameters

Even when two functions share the same set of parameter types, reordering those types — like void combine(int a, double b) versus void combine(double a, int b) — creates two genuinely distinct, valid overloads, since the compiler still sees them as different parameter signatures.

Example: Overloading by Order of Parameters

cpp
#include <iostream>

void combine(int a, double b) { std::cout << "int,double: " << a << "," << b << std::endl; }
void combine(double a, int b) { std::cout << "double,int: " << a << "," << b << std::endl; }

int main() {
	combine(1, 2.5);
	combine(2.5, 1);
	return 0;
}

Best Practices in Overloading

Overloaded functions with the same name should perform genuinely related, conceptually similar tasks — for example, several area() overloads for different shapes — rather than being unrelated operations that just happen to share a convenient name. Reusing a name for unrelated behavior makes code harder to understand at a glance.

Example: Best Practices in Overloading

cpp
#include <iostream>

double area(double side) { return side * side; }
double area(double length, double width) { return length * width; }

int main() {
	std::cout << area(4.0) << std::endl;
	std::cout << area(3.0, 5.0) << std::endl;
	return 0;
}

Resolving Overload Ambiguity

The compiler occasionally can't determine which overload you meant, usually when an argument's type is ambiguous between two candidates — passing a literal 0 where both an int and a pointer overload exist is a classic example. When this happens, you'll get a compile-time 'ambiguous call' error rather than a silent wrong choice, which at least surfaces the problem immediately.

Example: Resolving Overload Ambiguity

cpp
#include <iostream>

void show(int x) { std::cout << "int: " << x << std::endl; }
void show(double x) { std::cout << "double: " << x << std::endl; }

int main() {
	show(5);      // clearly int
	show(5.0);    // clearly double
	// show('a'); // ambiguous-prone: char can convert to either
	return 0;
}

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.