派生类中的using-declaration不会隐藏从基类派生的相同函数

Liu*_*ick 25 c++ using-declaration

看看下面的代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

根据我的理解,B::f()in C应该隐藏使用声明A::f()带来的内容C; 如果是的话,为什么c.C::f()还要打电话A::f()

如果c.C::f()调用A::f(),这应该意味着,在范围C,f()应始终参考A::f(),这是使用声明的功能.然后为什么在C::test(),呼叫f()仍然评估B::f()

Rei*_*ica 29

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

基本上,当f在范围内查找名称时C,它总是会A::f因使用声明而找到.因此,所有的通话c.f(),c.C::f()以及f()C::test(),解析名称fA::f.

接下来是虚拟调度.如果通过非限定名称调用虚函数,则会发生动态调度并调用最终的覆盖.这涵盖c.f()f()呼吁C::test(),因为这些是不合格的.

该调用c.C::f()使用限定名称f,该名称禁止动态调度以及直接调用名称解析的函数.由于该功能A::f(由于使用声明),因此A::f被称为非虚拟的.相关规则如下(引用C++ 14最终草案N4140,强调我的):

10.3节/ 15

使用范围运算符(5.1)进行显式限定可以抑制虚拟调用机制.

§5.2.2/ 1

...如果所选函数是非虚拟的,或者类成员访问表达式中的 id- expression是qualified-id,则调用该函数.否则,调用对象表达式的动态类型中的最终覆盖(10.3); 这种调用称为 虚函数调用.