Difference Between Function Overloading and Overriding in C++
Video Tutorial
Overview
In C++, two or more functions can have the same name if the number or the type of parameters are different. This is function overloading, whereas function overriding is the redefinition of a base class function in its derived class with the same signature.
Scope
- This article covers the concepts of function overloading and function overriding in C++.
- It covers the difference between function overloading and function overriding in C++.
Pre-requisites:
- An understanding of functions.
- C++ inheritance, constructor, and basic knowledge of C++.
Introduction
Functions are a way to bind together code that is meant to be called repeatedly. After all, you wouldn’t want to copy-paste that code of yours again and again, right? What if you needed to modify that code? You would need to change the code at every instance mindlessly. That is one of the reasons functions are one of the essential parts of procedural programming.
But, there are instances where you would need the function's alias (the name) to be reused depending upon the context. This is what we call polymorphism. Polymorphism means multiple forms (poly-morphisms), so in our instance, we mean that the function alias will have multiple forms! One good example of polymorphism is:
We make sounds via talking but so do other animals. So, if we were to design an interface for Animals, makeSound() would be a common interface for all.
Function Overloading in C++
- Let’s consider a situation: Say you wanted to create a program that would return the area of the rectangle. Say if I provided length(say x) and breadth(say y), you would return x*y. You would probably write this code:
- So far, so good. Until your supervisor tells you that people also want to calculate the area of a square using the same function. Now, you want to calculate the area based on how many arguments are passed to the function. Say if I were provided just x (just one argument), you would assume that I’m calculating the area of a square and return x*x. But if I provided x and y (so two arguments), you would return x*y. You would write the code something similar to this:
C++ can distinguish between the two contexts of function calls because the number of arguments differs in both instances.
- Apart from distinguishing based on the number of arguments, C++ can also distinguish the function calls based on the data type of the arguments passed to the function. Now, the supervisor is impressed and wants you to code for the condition of the circle if the user provided a floating value input. So if I were to pass a float value, you would return the area of the circle (3.14 * r * r), and if I were to pass int value, you would return x * x as before. I can define a third function that distinguishes based on the data type passed.
Side Note: One subtle problem with distinguishing based on the data type of function is type casting (i.e., a char type can be promoted to int or float or double). The C++ compiler follows a series of priorities when matching the function application:
- It first tries to match the exact type (int to int/float to float).
- If no match is found, it promotes the data type and retries (conversion between int to char and char to int or float to double and double to float).
- If still no match is found, the C++ compiler throws an error.
As can be seen, if functions are :
And if you called foo(‘a’, ‘a’) or foo(21, 21), the function call would be ambiguous, and the C++ compiler would throw an error; however, foo(‘a’, 21) or foo(21, ‘a’) would compile correctly. This is because the (char, char) or (int, int) can be internally promoted to either (char, int) or (int, char), which is why it is ambiguous. However, (char, int) and (int, char) have specific implementations.
This is what we call Function Overloading. We overload (redefine) the function alias to have different implementations and distinguish these based on the number of arguments or the data type.
These function overloading instances are a type of compile time polymorphism. The C++ compiler at compile time can easily deduce which function is being called by inspecting based on the above conditions. Internally, both the functions have different signatures (signature meaning the structure/layout of the function – the number/type of argument it accepts) and the compiled object code references the correct functions.
Function overriding in C++
Say, instead of writing functions, we wanted to define an OOP-based solution. First, we need to have a map of how we want to design these structures.
One solution is: to say I have a Rectangle class. Since we know that a Square is a Rectangle, we can create a subclass Square off a class Rectangle.
Output:
We know that child classes inherit all public data and methods from the parent class. So the Square class also inherits the area function. However, we redefine the area function as side * side. This redefinition of the area function is an example of function overriding. C++ knows that you specifically redefined the area function for the Square class. This overriding of function is a type of runtime polymorphism.
C++ distinguishes the function call at runtime instead of knowing it during compilation because the function signature is similar at compile time.
Function Overloading vs Function Overriding in C++
As we’ve seen before, function overloading and overriding play similar roles. They both provide an abstraction over the interface so that the end user doesn’t have to think much about the context and pass in the arguments. However, there are subtle differences between the two approaches.
Function Overloading | Function Overriding |
---|---|
Function overloading can be used in normal functions as well as in classes (e.g., constructor overloading is a classic example where you would vary the number/type of arguments for different initializations). | Function overriding applies exclusively to an inherited class (or in other words a subclass). |
Function overloading is resolved at compile time. | Function overriding is resolved at run time. |
Overloaded functions are in the same scope. | Overridden functions are in different scopes. |
Overloaded functions have different function signatures. | Overridden functions have the same function signatures. |
The key takeaway from this article is that both of these approaches are similar but, at the same time, quite different.
Conclusion
- Function overloading and overriding both seek to improve the interface and provide a consistent interface that should be intuitive to the user. They are used in different contexts.
- Function overloading is used when we want multiple functions providing a similar implementation.
- However, function overriding is used when we want to add some additional functionality on top of base class implementation.