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

时间:2015-02-11 08:03:24

标签: 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;
}

根据我的理解,B::f()中的C应该隐藏使用声明带来A::f()的{​​{1}};如果是的话,为什么C仍然会调用c.C::f()

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

1 个答案:

答案 0 :(得分:29)

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

基本上,当在f的范围内查找名称C时,由于using声明,总是找到A::f。因此,c.f()中的所有来电c.C::f()f()C::test()都会将名称f解析为A::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);这样的呼叫被称为a   虚拟函数调用。