For the next few points, it's important to differentiate between three common terms:
To overload a function f() means to provide another function with the same name (f) in
the same scope but with different parameter types. When f() is actually called, the
compiler will try to pick the best match based on the actual parameters that are supplied.
To override a virtual function f() means to provide another function with the same name
(f) and the same parameter types in a derived class.
To hide a function f() in an enclosing scope (base class, outer class, or namespace)
means to provide another function with the same name (f) in an inner scope (derived
class, nested class, or namespace), which will hide the same function name in an enclosing
scope.
void main()
{
Base b;
Derived d;
Base* pb = new Derived;
b.f(1.0);
No problem. This first call invokes Base::f( double ), as expected.
d.f(1.0);
This calls Derived::f( complex<double> ). Why? Well, remember that Derived doesn't declare
"using Base::f;" to bring the Base functions named f into scope, and so, clearly, Base::f( int
) and Base::f( double ) can't be called. They are not present in the same scope as Derived::f(
complex<double> ) so as to participate in overloading.
The programmer may have expected this to call Base::f( double ), but in this case there won't
even be a compile error, because, fortunately(?), complex<double> provides an implicit conversion
from double, so the compiler interprets this call to mean Derived::f( complex<double>(1.0) ).
pb->f(1.0);
Interestingly, even though the Base* pb is pointing to a Derived object, this calls Base::f(
double ), because overload resolution is done on the static type (here Base), not the dynamic type
(here Derived).
For the same reason, the call "pb->f(complex<double>(1.0));" would not compile, because there
is no satisfactory function in the Base interface