0

I'm failing to understand how can a grandchild (D) override a hidden (by C::f2(A&) method (B::f2(A)).

Here is an example code:

class B{
    public:
    virtual void f2(A a){cout<<"B::f2()"<<endl;}
};

class C:public B{
private:
    public:
    virtual void f2(A& a){cout<<"C::f2(A&)"<<endl;
    }

};

class D:public C{
    public:
    void f2(A a){cout<<"D::f2(A)"<<endl;}
};

int main(void)
{
    B* b = new D();
    A a2 = A();
    A &a = a2;
    b->f2(a); // prints D::f2 - should'nt it print B::f2??

    C* c = new D();
    c->f2(a); // prints C::f2 - as expected
    return 0;

}
Renat
  • 7,718
  • 2
  • 20
  • 34
sasha
  • 35
  • 7
  • Check this: https://stackoverflow.com/questions/7098054/virtual-qualifier-in-derived-class . `D::f2` is a virtual actually and overrides `B::f2` – Renat Jul 17 '19 at 16:44
  • 1
    But C::f2 hides B::f2. – sasha Jul 17 '19 at 16:50
  • 1
    No, it does not hide it. What makes you think it hides it? – Mike Nakis Jul 17 '19 at 16:54
  • @MikeNakis [Yes, it does](https://coliru.stacked-crooked.com/a/9eba15b55256affc) (though [that is fixable](https://coliru.stacked-crooked.com/a/02746f429240edd2) if you're so-inclined) – Lightness Races in Orbit Jul 17 '19 at 17:06
  • 1
    The rules for virtual function overrides simply don't look at visibility at all. (Or access: you can override a virtual private function of a base class too.) Not sure what other kind of "why" you're looking for. – aschepler Jul 17 '19 at 17:08
  • @aschepler But lookup happens before virtual dispatch happens, so calling `b->f2` will not find any function that takes `A`, regardless of whether that function is overridden. – Lightness Races in Orbit Jul 17 '19 at 17:09
  • 2
    @LightnessRacesinOrbit Sure. Lookup for `b->f2` finds `B::f2` and calls its final overrider which is `D::f2`. Lookup for `c->f2` finds `C::f2` which is its own final overrider. – aschepler Jul 17 '19 at 17:12

2 Answers2

2

The interface of B does not have f2( A& ), so if the compiler was not to make an implicit conversion, your b->f2( a ); would fail to compile.

But since the interface of B does have f2( A ), the compiler implicitly converts (*1) your a from type A& to type A. So, the function of the form f2( A ) is selected from the interface of B.

And since your D overrides that function, D's function ends up being invoked.

(*1) C++ die-hards might know of a more specific term than 'implicitly converts' for precisely what happens in these cases. But I am just an amateur.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
2

Why f2 in class B is overridden by f2 in class D

Because D::f2 has the same argument list. A function with same name and argument list overrides a virtual function in base, if such virtual function in base exists.

Whether the virtual function has been hidden by another function with same name in an intermediate base or not has no effect on this.

The rule from the standard (draft):

[class.virtual]

If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list ([dcl.fct]), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf overrides Base::vf.

So, to conclude, D::f2 overrides B::f2, because it has same argument list. It does not override C::f2, because the argument list is different.

Community
  • 1
  • 1
eerorika
  • 232,697
  • 12
  • 197
  • 326