This is purely a function of when a function is overridden in C++.
In C++, function overriding is done according to the "signature" of member functions:
- unqualified name
- exact parameters list in the declaration (excluding implicit
this
)
- qualification of the
this
implicit parameter
Obviously, by definition, the type of the this
parameter cannot match exactly, as by definition the type must be a pointer to a derived class.
[Note about cv-qualification on parameters:
The parameters in the declaration as seen by caller must be exactly the same, that is after removal of meaningless cv-qualifiers on object copies: these are cv-qualifiers on local variables inside the function body, and that's only meaningful in a function definition.
void f(const int i); // takes an int by value; const is meaningless
void f(int i); // redeclaration of the same function
// redeclaration of the same function yet again
void f(const int ci) { // const is meaningful here
ci = 1; // error
}
--end note]
However the same code, BUT with the child classes foo definition
being void foo(bool def = true)
Prints out Parent's foo.
Because there is no match of the parameters lists: an empty parameter list is only matched by an empty parameter list.
You need to replace the default argument with two overloaded functions here, with no forwarding to the other:
void foo(bool def); // new function signature
void foo() { // overrides Parent's member
foo(true);
}
With long complex a parameters list, it's easy to change a type and create a new function signature instead of overriding a base class virtual function; it's also easy to get the capitalisation wrong or spelling wrong (think English vs. US spelling). In general, getting the name of a function wrong (or any other name: of a type, of a template, of a variable...) causes a compilation error because that name with the small spelling change wasn't declared. But with a raw declaration of a member with the intent of overriding a base class declaration, there is no hint that you tried to do that and the compiler will not warn you (it might warn for hiding a base class declaration, but this is different). Explicitly marking a declaration intended to be an override with the virtual
keyword doesn't help, introducing a new virtual function isn't the intent.
That was the sad state of affairs after the first version of the C++ standard was formalized. Now it's different.
If you want to be sure that you are indeed overriding a base class declaration, you can now use the override
keyword:
class Child : public Parent
{
public:
void foo(bool def);
void foo() override {
foo(true);
}
};