Open In App

Does overloading work with Inheritance?

Improve
Improve
Like Article
Like
Save
Share
Report

If we have a function in base class and another function with the same name in derived class, can the base class function be called from derived class object? This is an interesting question and as an experiment, predict the output of the following C++ program: 

C++




#include <iostream>
using namespace std;
class Base
{
public:
    int f(int i)
    {
        cout << "f(int): ";
        return i+3;
    }
};
class Derived : public Base
{
public:
    double f(double d)
    {
        cout << "f(double): ";
        return d+3.3;
    }
};
int main()
{
    Derived* dp = new Derived;
    cout << dp->f(3) << '\n';
    cout << dp->f(3.3) << '\n';
    delete dp;
    return 0;
}


The output of this program is: 

f(double): 6.3
f(double): 6.6 

Instead of the supposed output: 

f(int): 6
f(double): 6.6 

Overloading doesn’t work for derived class in the C++ programming language. There is no overload resolution between Base and Derived. The compiler looks into the scope of Derived, finds the single function “double f(double)” and calls it. It never disturbs the (enclosing) scope of Base. In C++, there is no overloading across scopes and derived class scopes are not an exception to this general rule. (See this for more examples)

Reference: technical FAQs on www.stroustrup.com 

Now consider the Java version of this program: 

Java




class Base
{
    public int f(int i)
    {
        System.out.print("f (int): ");
        return i+3;
    }
}
class Derived extends Base
{
    public double f(double i)
    {
        System.out.print("f (double) : ");
        return i + 3.3;
    }
}
class myprogram3
{
    public static void main(String args[])
    {
        Derived obj = new Derived();
        System.out.println(obj.f(3));
        System.out.println(obj.f(3.3));
    }
}


The output of the above program is: 

f (int): 6
f (double): 6.6 

So in Java, overloading works across scopes, contrary to C++. The Java compiler determines the correct version of the overloaded method to be executed at compile time based upon the type of arguments used to call the method and the parameters of the overloaded methods of both these classes that receive the values of arguments used in call and executes that overloaded method.

Finally, let us try to get the output of the following C# program: 

C#




using System;                    
class Base
{
    public int f(int i)
    {
        Console.Write("f (int): ");
        return i + 3;
    }
}
class Derived : Base
{
    public double f(double i)
    {
        Console.Write("f (double) : ");
        return i+3.3;
    }
}
class MyProgram
{  
    static void Main(string[] args)
    {
        Derived obj = new Derived();
        Console.WriteLine(obj.f(3));
        Console.WriteLine(obj.f(3.3));
        Console.ReadKey(); // write this line if you use visual studio
    }
}


Note: Console.ReadKey() is used to halt the console. It is similar to getch() in C/C++. 
The output of the above program is: 

f(double) : 6.3
f(double):  6.6 

Instead of the assumed output: 

f(int) : 6
f(double) : 6.6 

Explanation: Here, the object we are creating is of the derived class, so the compiler will give preference to the derived class first and will perform implicit type casting if needed. So as soon as the compiler comes to “Console.WriteLine(obj.f(3));”, it will check for parameter compatibility. Here, the value 3 is of type int which is compatible with the parameter type double of derived class function f. So the compiler will perform the implicit type conversion of int to double. Hence the output f(double) : 6.3 will come. 

Now when the compiler comes to “Console.WriteLine(obj.f(3.3));”, again it will give preference to the derived class first and will find it callable. So it will evaluate the derived class function f. Hence the output f(double): 6.6 will come.

Now let’s take another case where we are putting the base class function f into derived class and vice-versa as shown below:

C#




using System;                    
class Base
{
    public double f(double i)
    {
        Console.Write("f (double) : ");
        return i+3.3;
    }
}
 
class Derived : Base
{
 
    public int f(int i)
    {
        Console.Write("f (int): ");
        return i + 3;
    }
     
}
 
class MyProgram
{
    static void Main(string[] args)
    {
        Derived obj = new Derived();
        Console.WriteLine(obj.f(3));
        Console.WriteLine(obj.f(3.3));
        Console.ReadKey(); // write this line if you use visual studio
    }
}


Output: 

f (int): 6
f (double) : 6.6

Are you shocked to see the expected output? How is it possible? 
Well, we have an answer to these questions. As the object we have created is of the derived class, the C# compiler will give first preference to derived and if it does not find any compatibility, then it goes for the base class. So when the compiler comes to “Console.WriteLine(obj.f(3));”, it will check the derived class method f and finding it callable, the compiler will execute this and the output f (int): 6 comes. Now when the compiler comes to “Console.WriteLine(obj.f(3.3));”, it will check the derived class method and find out that it is not suitable as the value 3.3 (double) is not compatible with the int data type. Hence the compiler will now prefer the base class and there it will find the best match, so it will execute that one. So the output for that one will be f (double) : 6.6.

The reason is the same as explained in the case of the C++ program. In C#, just like in C++, there is no overload resolution between class Base and class Derived. Also, there is no overloading across scopes and derived class scopes are not an exception to this general rule. This is same as C++ because C# is designed to be much closer to C++, according to Anders Hejlsberg, the creator of the C# language.

 



Last Updated : 22 Jun, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads