If we have a function in base class and a function with 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.
#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 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 with the (enclosing) scope of Base. In C++, there is no overloading across scopes – derived class scopes are not an exception to this general rule. (See this for more examples)
Now consider Java version of this program:
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++. Java compiler determines correct version of the overloaded method to be executed at compile time based upon the type of argument used to call the method and parameters of the overloaded methods of both these classes receive the values of arguments used in call and executes the overloaded method.
Finally, let us try the output of following C# program:
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 as 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, we are creating the object 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 compiler comes at Console.WriteLine(obj.f(3)); this line of code it will check for the parameters compatibility. Here the 3 is int which is compatible with the double of derived class function f. So compiler will perform the implicit type conversion of int to double. Hence the output f(double) : 6.3 will come.
Now when compiler goes at Console.WriteLine(obj.f(3.3));, again it will give the preference to the derived class and it finds callable. So it will evaluate the dervied 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:
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