Names in derived classes hide names in base classes, which is not desirable in public inheritance. To fix it, employ using
declarations or forwarding functions to make hidden names visible again.
As we all know, names in inner scopes hide (“shadow”) names in outer scopes. Specifically, whether the names correspond to the same or different types is immaterial. In the world of inheritance, the scope of a derived class is nested inside its base class’s scope, so if we define following classes:
|
|
|
|
When compilers see the use of the name mf2
here, they figure out what it refers to by searching scopes for a declaration of something named mf2
by following order:
- first they look in the local scope of
mf4
- then they search the containing scope, that of the class
Derived
- they move on to the next containing scope, that of the base class (there they found something named
mf2
, so the search stops) - if there were no
mf2
inBase
, the search will continue, first to the namespace(s) containingBase
, and finally to the global scope
Consider again what will happen if the two classes are defined in the following way, with mf1
and mf3
overloaded in Base
and a new mf3
added in Derived
:
|
|
|
|
From the perspective of name lookup, Base::mf1
and Base::mf3
are no longer inherited by Derived
, because all functions names mf1
and mf3
in the base class are hidden by the functions names mf1
and mf3
in the derived class. This leads to following behavior:
|
|
Even though the functions in the base and derived classes take different parameter types, and no matter those functions are virtual or non-virtual, the name lookup rule applies regardlessly. The rationale behind this behavior is to prevent us from accidentally inheriting overloads from distant base classes when we create a new derived class in a library or application framework. However, sometimes we want to inherit the overloads1.
To access the hidden names, we have two ways to go: using
declarations and forwarding function.
using
declarations
|
|
And now inheritance will work as expected:
|
|
This tells us that
if we inherit from a base class with overloaded functions and we want to redefine or override only some of them, we need to include a
using
declaration for each name we’d otherwise be hiding. If we don’t, some of the names we’d like to inherit will be hidden.
Unser public inheritance, we always want to inherit all the functions from the base classes to follow public inheritance’s is-a relationship between base and derived classes, which is why the using
declarations above are in the public part of the derived class (names that are public in a base class should also be public in a publicly derived class).
However, under private inherits (item 39), it can make sense to inherit only part of the functions from the base classes. A the using
declaration won’t do the trick here, for it makes all inherited functions with a given name visible in the derived class. We use a different technique: forwarding function.
Forwarding function
|
|
|
|
For ancient compilers that don’t support using
declarations, we also have to use forwarding function technique to import inherited names into the scope of derived classes.
When inheritance is combined with templates, an entirely different form of the “inherited names are hidden” issue arises. See item 43 for all the angle-bracket-demarcated details.
-
In fact, in public inheritance, if we don’t inherit the overloads, we’re violating the is-a relationship between base and derived classes, which, as explained in item 32, is fundamental to public inheritance. ↩︎