Search code examples
c++virtual-functionsoverload-resolution

Resolution of virtual function with default parameters


header.h

#include <iostream>
using namespace std;
class A
{
    public:
        virtual void display(int i=5) { cout<< "Base::" << i << endl; }
};

class B : public A
{
    public:
        void display(int i=9) { cout<< "Derived::" << i << endl; }
};  

source.h

#include <iostream>
#include "header.h"
using namespace std;
int main()
{
    A * a = new B();
    a->display();

    A* aa = new A();
    aa->display();

    B* bb = new B();
    bb->display();
}  

output

Derived::5
Base::5
Derived::9  

My understanding was default parameter functions were resolved during compile time using function overloading. Virtual functions were then resolved during runtime using function overriding.

But what is happening is a mess.
How does the function resolution actually happen here?


Solution

  • Your code is actually seen by the compiler like this:
    (The display() method is not actually there, but the resolving works in similar way)

    class A
    {
    public:
        virtual void display(int i) { cout<< "Base::" << i << endl; }
        void display() { display(5); }
    };
    
    class B : public A
    {
    public:
        void display(int i) override { cout<< "Derived::" << i << endl; }
        void display() { display(9); }
    };
    

    Now you should understand what happens. You are calling the non-virtual display() which calls the virtual function. In more strict words: the default argument is resolved just like if the no-arg non-virtual method was there - by the type of the variable (not by the actual type of the object), but the code gets executed according to real object type, because it is virtual method:

    int main()
    {
        A * a = new B(); // type of a is A*   real type is B
        a->display();    // calls A::display() which calls B::display(5)
    
        A* aa = new A(); // type of aa is A*  real type is A
        aa->display();   // calls A::display() which calls A::display(5)
    
        B* bb = new B(); // type of bb is B*  real type is B
        bb->display();   // calls B::display() which calls B::display(9)
    }