25

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()?

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
Liu Nick
  • 349
  • 2
  • 9

1 Answers1

29

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.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • @LiuNick The Stack Overflow way of saying "thanks" is to [accept the answer which solved the problem](http://stackoverflow.com/help/someone-answers) (at most one accepted answer per question). This marks the question as solved, and gives both the answerer and you some reputation. – Angew is no longer proud of SO Feb 11 '15 at 10:05