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...).