4.1. Function overloads

Unlike C, in C++, two different functions can have the same name as long as their parameter lists are different. When two functions have the same name, but different parameters, the functions are said to be overloaded.

In order to count as a valid overload, either the number of parameters must be different, or the parameter types must be different, or a combination of both. For example:

 1#include <iostream>
 2using std::cout;
 3
 4// add two ints
 5constexpr int add (int a, int b) {
 6  return a+b;
 7}
 8// add two doubles
 9constexpr double add (double a, double b) {
10  return a+b;
11}
12
13int main () {
14  int x=5, y=2;
15  double p=3.14, e=2.718;
16  cout << add (x,y) << '\n';
17  cout << add (p,e) << '\n';
18
19  // error: call to overloaded function add (double, int) ambiguous
20  // cout << add (31.4, 10) << '\n';
21
22  // explicit conversion is OK
23  cout << add (31.4, double(10)) << '\n';
24}

Function overloads are a huge advantage over C where (nearly) every function is global and every function name must be unique. For example:

  • C defines 7 different functions just for absolute value

    • abs, llabs, fabs, fabsf, etc. see abs

  • and 13 different functions for different types of division operations

This just adds to the amount of stuff programmers have to commit to memory. In C++, you only have to remember a single function to compute the absolute value: abs.

Open video

Another example: a family of functions to compute volume.

 1#include <cmath>
 2#include <iostream>
 3#include <numbers>
 4
 5// volume of a cube
 6constexpr double volume (const double a) {
 7  return a * a * a;
 8}
 9
10// volume of a cylinder
11constexpr double volume (const double r, const double h) {
12  // starting with C++20, numeric constants are preferred over
13  // macros like `M_PI`
14  return std::numbers::pi * r * r * h;
15}
16
17// volume of a cuboid
18constexpr double volume (const double a, const double b, const double c) {
19  return a * b * c;
20}
21
22int main() {
23  std::cout << "volume of a 2 x 2 x 2 cube: "
24            << volume(2) << '\n'
25
26            << "volume of a cylinder, radius 2, height 3: "
27            << volume(2, 3) << '\n'
28
29            << "volume of a 2 x 3 x 4 cuboid: "
30            << volume(2, 3, 4) << '\n';
31  return 0;
32}

Note

The return type is not part of the overload.

Two functions in the same namespace that differ only in return type will not compile.

4.1.1. Overloading anti-patterns

How many parameters are too many?

This is an often asked question, with no clear cut answer. It is primarily a question of clarity and design.

For example, given:

int operate (float a, int b, long c, double d);

In this case, the parameters and function name provide no guidance on how to call this function. So four is probably too many parameters, simply because future usage errors are likely.

Keep in mind that more parameters equal more complexity. Limit the number of parameters you need in a given method, or use a struct to combine parameters. Also, be wary of overloads with the same number of parameters and different types. For example:

int operate (double a, int b);
int operate (int a, double b);

Depending on what operate does with it's parameters, reversing the order of the parameters could have drastic consequences. We just don't know without looking at the source code. In this case even two parameters is too many. It is almost certain someone will invoke the wrong version occasionally.


More to Explore

  • From: cppreference.com: overload resolution

  • Item 08: Prefer nullptr to 0 and NULL. 'Effective Modern C++', by Scott Meyers (O’Reilly). Copyright 2015 Scott Meyers, 978-1-491-90399-5.