Sorry, quirkyusername's answer is not quite true. While the derived version does hide
the base version, the base can still be called, however you have to use scoping. Example:
1 2 3 4 5 6 7 8 9 10 11
|
class Base {
virtual void foo( int x ) { }
};
class Derived {
virtual void foo( double d ) { }
void some_member_function() {
Base::foo( 3.14 );
}
};
|
And as for the second question, if your virtual method contains default parameters,
for the sake of sanity, ensure that overrides of the method in derived classes use
the same default value! The reason is that the answer depends upon what
declarations the compiler has seen and what the compiler knows about the object.
Consider this example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
#include <iostream>
struct Base {
virtual void foo( int x = 20 ) { std::cout << x << std::endl; }
};
struct Derived : Base {
virtual void foo( int x = 10 ) { std::cout << x << std::endl; }
};
void frobnicate( Base& b ) {
b.foo();
}
int main() {
Derived d;
d.foo(); // Outputs 10, as expected
frobnicate( d ); // Outputs 20!!!
}
|
The same object outputs two different answers! Why? Because when the compiler
is compiling
d.foo();
in main(), the compiler knows that d is an instance
of Derived, so it looks at Derived's declartaion of foo, as we'd expect, and assumes
that we wanted to implicitly pass 10 to foo().
But when the compiler is compiling
b.foo();
in frobnicate(), the compiler
doesn't know the actual type of its parameter; it only knows that it is either a
Base or
something derived from Base. So the only foo() it can look at is Base's,
so in this case it assumes we wanted to call foo() with 20 instead of 10.