Search code examples
c++using-declaration

using-declaration in derived class does not hide same function derived from base class


Have a look at the following code:

struct A {
public:
    virtual void f(){std::cout << "in A";};
};

struct B : A{
public:
   virtual void f(){std::cout << "in B";};
   int a;
};

struct C : B{
    using A::f;
    void test(){f();}
};


int main() 
{
    C c;
    c.f(); // calls B::f, the final overrider
    c.C::f(); // calls A::f because of the using-declaration
    c.test(); //calls B::f
    return 0;
}

Per my understanding, the B::f() in C should hide the A::f() which is brought to C by using-declaration; if so, then why does c.C::f() still call A::f()?

If c.C::f() calls A::f(), that should mean that in the scope of C, f() should be always refer to A::f(), this is the function of the using-declaration. Then why in the C::test(), call to f() is still evaluated to B::f()?


Solution

  • Very nice question, a complicated case of name lookup.

    Basically, when the name f is looked up in the scope of C, it always finds A::f due to the using-declaration. So all the calls c.f(), c.C::f(), and f() in C::test(), resolve the name f to A::f.

    Next comes virtual dispatch. If a virtual function is called by an unqualified name, dynamic dispatch happens and the final overrider is called. This covers c.f() and the f() call in C::test(), since these are unqualified.

    The call c.C::f() uses a qualified name for f, which suppresses dynamic dispatch and the function to which the name resolved is called directly. Since that function is A::f (thanks to the using-declaration), A::f is called non-virtually. The relevant rules follow (quoting C++14 final draft N4140, emphasis mine):

    §10.3/15

    Explicit qualification with the scope operator (5.1) suppresses the virtual call mechanism.

    §5.2.2/1

    ... If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called. Otherwise, its final overrider (10.3) in the dynamic type of the object expression is called; such a call is referred to as a virtual function call.