I'm having a problem with C++ inheritance.
I have a class hierarchy:
class A {
public:
virtual void onFoo() {}
virtual void onFoo(int i) {}
};
class B : public A {
public:
virtual void onFoo(int i) {}
};
class C : public B {
};
int main() {
C* c = new C();
c->onFoo(); //Compile error - doesn't exist
}
My question is: why doesn't this compile? My understanding is that C should inherit both onFoo functions from A - and in fact, this compiles if you remove the redefinition of onFoo in B - but g++ gives an error that C has no onFoo() function.
This is name hiding, basically only the declared overrides exist in B and the other overloads in A are hidden.
Methods on class A and B should be public. That, and you are missing semi-colons at the end of each class declaration.
You forgot
public:
modifier before methods in both class A and B. Therefore method onFoo is private and thus not visible anywhere outside these classes.The issue that you are experiencing is related to how name lookup works in C++. In particular, when resolving a member, the compiler will look into the static type of the object on which the member is being accessed. If the identifier is found in that class, then lookup completes and (in the case of member functions) overload resolution starts. If the identifier is not found, it will crawl up the hierarchy, class by class, trying to locate the identifier one level at a time.
In your particular case, you have
c->onFoo();
andc
is of typeC
. The compiler does not see any declaration ofonFoo
inC
, so it continues upwards in the hierarchy. When the compiler checksB
, it sees that there is a declaration ofvoid onFoo(int i)
at that level, so it stops lookup, and tries overload resolution. At this time, the overload resolution fails due to the inconsistency in the arguments.The fact that a declaration of
void onFoo(int)
is present atB
level has the effect of hiding the rest of the overloads in any base class, as it will stop lookup. Note that this is a problem with unqualified lookup, the function is still there and applicable to the object, but will not be found by regular lookup (you can still call it asc->A::onFoo()
).As of how to deal with hiding, the simplest way is by employing the using declaration to bring the functions into scope:
The effect of the
using
declaration here is that when theB
class is looked up, in search for theonFoo
identifier, the compiler is instructed to also consider all overloads ofonFoo
in the base class, enabling regular lookup to findA::onFoo()
.If you want base class members to overload derived class members, you want to use
using
:I guess you have missed adding this in
class B
:Now this compiles!