6

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?

cppcoder
  • 22,227
  • 6
  • 56
  • 81
  • 1
    `Default argument resolution is based on the static type of the object through which you call the function` (i.e. based on the pointer type). http://social.msdn.microsoft.com/Forums/en-US/90b9b8ee-ed5f-4ba8-93b5-612c4d906124/default-argument-and-inheritance-hierarchy – Andreas Fester Sep 23 '14 at 12:06
  • Note that you can work around this problem by overloading the virtual function with another virtual function without the paramter, which "forwards" to the one with the parameter. Like: in Base `virtual void display() { display(9); }` and in Derived `void display() { display(5); }` – leemes Sep 23 '14 at 12:13

3 Answers3

8

There is no polymorphism on default arguments. They are resolved compile-time.

A::display has default argument equal 5. B::display has default argument equal 9. It's only the type of a, aa, bb variables that matters.

Use of different default arguments in polymorphic methods is confusing and should be avoided.

0xF
  • 3,214
  • 1
  • 25
  • 29
  • I'm sorry but I don't understand: why `a->display()` is showing `Derived::5` and `bb->display()` is showing `Derived::9`? They are defined in exactly the same way... – Stefano Falsetto Sep 23 '14 at 12:15
  • 2
    @StefanoF Because `a` is of type `A*` while `bb` is of type `B*`. Hence, `a->display()` uses the declaration from `class A` while `bb->display()` uses the one from `class B` – Andreas Fester Sep 23 '14 at 12:16
8

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)
}  
firda
  • 3,268
  • 17
  • 30
  • 1
    Oh, this is exactly what I was looking for.Hey, but then how is `Derived::5` printed? It should be `Base::5` – cppcoder Sep 23 '14 at 12:11
  • When you invoke `a->display();` on an object of (dynamic) type `B`, it calls `display();`, that is the **non-virtual overload** `display()` which calls `display(5);` which is then **virtually** resolved to `B::display(5)`. And in the original code something similar happens. Instead of the additional non-virtual function, it is the default parameter which is resolved on the **static type**. – leemes Sep 23 '14 at 12:14
  • 2
    Hmm, this is complicated. – cppcoder Sep 23 '14 at 12:15
  • 2
    Note that firda's code is only a demonstration for better understanding what happens under the hood. The compiler does not really translate your code to this one. – leemes Sep 23 '14 at 12:16
  • @leemes I think, then it is a different question to ask how functions with default parameters are resolved? – cppcoder Sep 23 '14 at 12:18
  • Yeah but I'm sure it exists. I recommend you to read the linked question (duplicate). – leemes Sep 23 '14 at 12:19
  • I read it. But that didn't say how the functions gets resolved. – cppcoder Sep 23 '14 at 12:20
  • @cppcoder: [see the answer from Andreas](http://stackoverflow.com/a/25994811/1722660). I have placed non-virtual `display()` on both classes taking the default argument to *mimic* how it works, how it is resolved. – firda Sep 23 '14 at 12:22
6

This behaviour is specified in Chapter 8.3.6: Default arguments within Programming languages — C++ (ISO/IEC 14882:2003(E)) :

A virtual function call (10.3) uses the default arguments in the declaration of the virtual function determined by the static type of the pointer or reference denoting the object

Andreas Fester
  • 36,091
  • 7
  • 95
  • 123