Code executes derived class method, but gets default parameter from base class method
Asked Answered
C

3

7

Can someone explain why the result of the code below would be "class B::1" ?

Why does the virtual method of derived class uses the default parameter of a base class and not his own? For me this is pretty strange. Thanks in advance!

Code:

#include <iostream>

using namespace std;

class A
{
public:
    virtual void func(int a = 1)
    {
        cout << "class A::" << a;
    }
};

class B : public A
{
public:
    virtual void func(int a = 2)
    {
        cout << "class B::" << a;
    }
};

int main()
{
    A * a = new B;
    a->func();

    return 0;
}
Cheroot answered 3/6, 2012 at 15:7 Comment(0)
T
6

Because default arguments are resolved according to the static type of this (ie, the type of the variable itself, like A& in A& a;).

Modifying your example slightly:

#include <iostream>

class A
{
public:
    virtual void func(int a = 1)
    {
        std::cout << "class A::" << a << "\n";
    }
};

class B : public A
{
public:
    virtual void func(int a = 2)
    {
        std::cout << "class B::" << a << "\n";
    }
};

void func(A& a) { a.func(); }

int main()
{
    B b;
    func(b);
    b.func();

    return 0;
}

We observe the following output:

class B::1
class B::2

In action at ideone.

It is not recommended that a virtual function change the default value for this reason. Unfortunately I don't know any compiler that warns on this construct.


The technical explication is that there are two ways of dealing with default argument:

  • create a new function to act as trampoline: void A::func() { func(1); }
  • add-in the missing argument at the call site a.func() => a.func(/*magic*/1)

If it were the former (and assuming that the A::func was declared virtual as well), then it would work like you expect. However the latter form was elected, either because issues with virtual were not foreseen at the time or because they were deemed inconsequential in face of the benefits (if any...).

Thanks answered 3/6, 2012 at 15:25 Comment(0)
T
5

Because default value is substituted during compilation and is taken from declaration, while real function to be called (A::func or B::func) is determined at runtime.

Tricksy answered 3/6, 2012 at 15:10 Comment(0)
C
5

Because polymorphism in C++ takes effect at run-time, whereas the substitution of default parameters takes effect at compile-time. At compile time, the compiler does not know (and is not supposed to know) the dynamic type of the object to which the pointer a points. Hence, it takes the default argument for the only type it knows for a, which in your example is A *.

(This incidentally is also the reason default parameters are given in interfaces/headers rather than in implementations/definitions. The compiler never inserts the default parameter in the implementation's machine code, but only in the caller's machine code. Technically, the default parameter is the property of the caller; and the caller doesn't know -- and shouldn't need to know -- an object's dynamic type.)

Croner answered 3/6, 2012 at 15:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.