C++ Virtual function being hidden

10,717

Solution 1

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(); and c is of type C. The compiler does not see any declaration of onFoo in C, so it continues upwards in the hierarchy. When the compiler checks B, it sees that there is a declaration of void 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 at B 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 as c->A::onFoo()).

As of how to deal with hiding, the simplest way is by employing the using declaration to bring the functions into scope:

class B : A {
public:
   using A::onFoo; // All A::onFoo overloads are *considered* here
   void onFoo( int );
};

The effect of the using declaration here is that when the B class is looked up, in search for the onFoo identifier, the compiler is instructed to also consider all overloads of onFoo in the base class, enabling regular lookup to find A::onFoo().

Solution 2

If you want base class members to overload derived class members, you want to use using:

struct A
{
   virtual void onFoo() {}
   virtual void onFoo(int i) {}
};

struct B : A
{
    using A::onFoo;
    virtual void onFoo(int i) {}
};

struct C : B
{
};


int main()
{
    C* c = new C();
    c->onFoo();
}

Solution 3

This is name hiding, basically only the declared overrides exist in B and the other overloads in A are hidden.

Solution 4

Methods on class A and B should be public. That, and you are missing semi-colons at the end of each class declaration.

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
}

Solution 5

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.

Share:
10,717

Related videos on Youtube

Nathaniel Flath
Author by

Nathaniel Flath

Student in Software Engineering at the University of Waterloo.

Updated on November 12, 2020

Comments

  • Nathaniel Flath
    Nathaniel Flath over 3 years

    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.

  • Ben Voigt
    Ben Voigt almost 13 years
    Those are valid points, but your "fix" doesn't compile either.
  • Nathaniel Flath
    Nathaniel Flath almost 13 years
    Whoops - that wasn't the issue, that was just me transcribing the problem wrong. Edited to fix