Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading of virtual functions

I was asked this question in an interview. I was not able to answer this there. Neither am I able to get it now, as to why the output is the way it is. Here is the code:

#include <iostream>
using namespace std;

class Base
{
public:
    virtual void fun ( int x = 0)
    {
        cout << "Base::fun(), x = " << x << endl;
    }
};

class Derived : public Base
{
public:
    virtual void fun ( float x = 10.0 )
    {
        cout << "Derived::fun(), x = " << x << endl;
    }
};


int main()
{
    Derived d1;
    Base *bp = &d1;
    bp->fun();
    d1.fun();
    d1.fun(1.2);
    return 0;
}

The output of the above code is:

Base::fun(), x = 0
Derived::fun(), x = 10
Derived::fun(), x = 1.2

The problem is: In the first case we say that both the fun() functions get overloaded (and not overridden since they differ in their declarations) and the base fun() gets called, but it is not possible for these declarations of fun() to be overloaded (since they differ only whether the declaration contains default argument or not)

void fun(int x = 0)
void fun(float x = 10.0)

It is not possible for these functions to get overloaded.

There seems to be a contradiction in both the above cases.

Any related article/ link explaining the situation would be highly helpful.

like image 724
Yaman K Singla Avatar asked Mar 15 '17 17:03

Yaman K Singla


1 Answers

In C++, for a member function to override a base class function, the argument types have to exactly match the base class function's argument types. Since the base class function takes in an int and your derived class's function takes in a float, it's not considered an override. You can see this by using the override keyword:

class Base
{
public:
    virtual void fun ( int x = 0)
    {
        cout << "Base::fun(), x = " << x << endl;
    }
};

class Derived : public Base
{
public:
    virtual void fun ( float x = 10.0 ) override // Doesn't compile!
    {
        cout << "Derived::fun(), x = " << x << endl;
    }
};

What's happening in your code is that C++ considers your function to be an overload (another function with the same name) rather than an override. Let's look at this code:

Derived d1;
Base *bp = &d1;
bp->fun();

Here, since the line bp->fun() uses a call through a base class pointer, C++ looks in Base to see which function to call. It finds Base::fun(int). Now, since that function is marked virtual, it will call Base::fun(int) unless something overrode it. But since there isn't an override, Base::fun(int) ends up getting invoked.

So what about these later two lines?

d1.fun();
d1.fun(1.2);

Here, since you're calling these functions on objects of static type Derived, C++ tries to find a function called fun in the Derived class. It finds your new function Derived::fun(float), and due to the way C++ does name lookup in classes it does not look in the base class to find Base::fun(int). Therefore, both of these calls are treated as calls to Derived::fun(float), so there's no ambiguity about which function to call when no arguments are presented. The compiler never even looked in the Base type because there was no need to.

So, to summarize:

  • You've introduced an overload, not an override. Using the override keyword would help you diagnose issues like this in the future.
  • Calling fun through the base pointer looks for a function named fun taking in an int, since the base pointer's fun function takes in an int. That finds the version in Base because there's no oerride.
  • Calling fun through the derived object looks for a function named fun starting in Derived, and it finds your override.
like image 82
templatetypedef Avatar answered Sep 21 '22 00:09

templatetypedef