When you’re writing code, usually you want it to be as intuitive and efficient as possible. After all, no one wants to manually write out repetitive code if they don’t need to. One of the key ways this is managed in object-oriented programming (OOP) languages is through function overloading. In this article, we’re going to explain in simple terms what function overloading is, why and how it’s used and illustrate this with examples.
What is Function Overloading and What is it Used For?
Function overloading is also known as compile-time polymorphism. This is because it’s one of the ways to achieve polymorphism in C++, which is where different types of objects can be treated as if they were the same. This eliminates the need to know the specifics of each kind of object, and it makes the code reusable and versatile.
Function overloading is known as compile-time polymorphism because it occurs before the program is executed, and allows several functions to have the same name but with different parameters. Depending on the arguments being passed, the necessary function is called during runtime. This means that we don’t need to duplicate functions unnecessarily, and code can be modified easier. The other type of polymorphism is known as runtime polymorphism, or function overriding. This is where a derived class has a different implementation of a method to the parent class, and this method is called when an instance of the object in question is created.
Within function overloading, there are two main types. These are either based on the number of parameters, or the type of parameters. We’ll illustrate these in turn.
Function Overloading in C++ – Examples
First, consider the following functions:
void print();
void print(int num);
void print(float num1, float num2);
Here, we have the same “print()” function, but with differing numbers of parameters and types. The first function has no parameters, while the subsequent functions have one and two parameters respectively. These parameters are of two different types – integer and float.
To see them in action, take a look at this code:
#include <iostream>
using namespace std;
void print();
void print(int num);
void print(float num1, float num2);
int main() {
print();
print(5);
print(2.5, 3.5);
return 0;
}
void print() {
cout << "Hello!" << endl;
}
void print(int num) {
cout << "The number is " << num << endl;
}
void print(float num1, float num2) {
cout << "The numbers are " << num1 << " and " << num2 << endl;
}
Here, we define the 3 functions as written before, then we define the “main()” function. This function calls each of the print functions but takes different arguments. We start by calling the print functions with no arguments, which returns the “Hello!” message by itself. Then, we call the print function with the integer argument, and then the function with the integer parameter is called. Finally, we call the print function with the float argument, and the function with two float parameters is called. These results are printed to the console and can be seen in the image below.

©History-Computer.com
What Errors Can Occur with Function Overloading in C++?
While function overloading provides a way to save time, energy, and a headache when it comes to coding, this is dependent on using it correctly. The most common errors are ambiguity errors, inheritance errors, and implicit conversion errors. We’ll cover these next.
Ambiguity errors
This is where the compiler cannot determine which function to use, usually if they have equivalent parameter types and numbers. For example, consider this modified code of the previous example:
#include <iostream>
using namespace std;
void print();
void print(int num);
void print(float num1, float num2);
void print(int num1, int num2);
int main() {
print();
print(5);
print(2.5, 3.5);
print(1, 2);
return 0;
}
void print() {
cout << "Hello!" << endl;
}
void print(int num) {
cout << "The number is " << num << endl;
}
void print(float num1, float num2) {
cout << "The numbers are " << num1 << " and " << num2 << endl;
}
void print(int num1, int num2) {
cout << "The numbers are " << num1 << " and " << num2 << endl;
}
We’ve introduced an additional print function that takes two integer parameters. When we call the print function, the compiler isn’t sure which function to call, the new function or the original (int num) function. Therefore, when we try to run the code, we receive the “Call to ‘print’ is ambiguous” error, as seen in the below image.

©History-Computer.com
Inheritance errors
When we use function overloading and inheritance together, we can encounter what is known as an inheritance error. If the method that the derived class is trying to inherit has the same name as other methods in the parent class, the correct method may not be inherited. To illustrate, we have the following code:
#include <iostream>
using namespace std;
class Shape {
public:
void draw() {
cout << "Drawing shape" << endl;
}
};
class Circle : public Shape {
public:
void draw() {
cout << "Drawing circle" << endl;
}
};
class Rectangle : public Shape {
public:
void draw(int width, int height) {
cout << "Drawing rectangle with width " << width << " and height " << height << endl;
}
};
int main() {
Circle c;
c.draw();
Rectangle r;
r.draw();
return 0;
}
We have the parent “Shape” class, and two derived classes, “Rectangle” and “Square”. The “draw()” virtual function from the parent class is overridden in both derived classes, but, in the “Rectangle” class, there is a new draw function that takes two parameters. Therefore, when trying to call the draw function on an instance of the “Rectangle” class, we get a compilation error. This is because the draw function wasn’t inherited properly from the parent class. This can be seen in the image.

©History-Computer.com
Implicit conversion errors
Implicit conversion refers to when the compiler converts one data type to the other for the code to make more sense, without explicit instruction from the programmer. For example, if we assign a float value to an integer variable, the compiler will convert the float value to an integer value before assigning it. We can illustrate this with this code:
#include <iostream>
using namespace std;
void print(double num) {
cout << "The double number is " << num << endl;
}
void print(int num) {
cout << "The integer number is " << num << endl;
}
int main() {
short x = 5;
print(x);
return 0;
}
We have two overloaded print functions here, with integer and double arguments. A double is a more precise type of float variable. The main function then tries to call the print function with the “x” variable. This is of the “short” type (a smaller integer type than “int”). This parameter isn’t taken by either print function. Therefore, the compiler implicitly converts it into the most accurate match, which is the integer type. In this way, the intended function wasn’t called. We receive the output “The integer number is 5”, which may not be what we want. This can be seen in the image.

©History-Computer.com
Function Overloading in C++: Wrapping Up
Function overloading is a crucial technique in OOP languages for making code reusable and reducing your workload. This is one type of overloading that’s used to achieve polymorphism. It’s useful when we have similar functions with the same name. However, it’s important to know how to overload functions effectively, to minimize the chance of errors.
The image featured at the top of this post is ©Monstar Studio/Shutterstock.com.