derived class 中的 using-declaration 不隐藏从 base class 派生的相同函数

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

看看下面的代码:

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;
}

根据我的理解,C 中的 B::f() 应该隐藏通过 using 声明带到 CA::f();如果是这样,那为什么 c.C::f() 仍然调用 A::f()

如果c.C::f()调用A::f(),那应该意味着在C的范围内,f()应该总是引用A::f(),这是使用声明的功能。那么为什么在 C::test() 中,对 f() 的调用仍然被评估为 B::f()

非常好的问题,一个复杂的名称查找案例。

基本上,当在 C 的范围内查找名称 f 时,由于使用-宣言。因此C::test()中的所有调用c.f()c.C::f()f(),都将名称f解析为A::f

接下来是虚拟调度。如果一个虚函数被一个不合格的名字调用,动态调度就会发生并调用最终的重写器。这包括 c.f()C::test() 中的 f() 调用,因为它们是不合格的。

调用 c.C::f() 使用 f 的限定名称,这会抑制动态调度,并直接调用名称解析到的函数。由于该函数是 A::f(多亏了 using 声明),因此 A::f 被非虚拟地调用。相关规则如下(引用C++14终稿N4140,强调我的):

§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.