【问题标题】:using-declaration in derived class does not hide same function derived from base class派生类中的使用声明不会隐藏从基类派生的相同函数
【发布时间】:2015-04-11 12:37:38
【问题描述】:

看看下面的代码:

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() 应该隐藏 A::f() 通过 using-declaration 带到 C;如果是这样,那为什么c.C::f() 仍然调用A::f()

如果c.C::f()调用A::f(),那应该是在C的范围内,f()应该总是引用A::f(),这就是using-declaration的作用。那为什么在C::test() 中,对f() 的调用仍然被评估为B::f()

【问题讨论】:

    标签: c++ using-declaration


    【解决方案1】:

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

    基本上,当在C 的范围内查找名称f 时,由于使用声明,它总是找到A::f。所以C::test()中的所有调用c.f()c.C::f()f(),将名称f解析为A::f

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

    调用c.C::f() 使用f 的限定名称,这会抑制动态调度和直接调用解析名称的函数。由于该函数是A::f(感谢使用声明),因此A::f 被非虚拟调用。相关规则如下(引用 C++14 final draft N4140,强调我的):

    §10.3/15

    作用域运算符的显式限定 (5.1) 抑制了虚拟调用机制。

    §5.2.2/1

    ...如果选择的函数是非虚拟的,或者如果 类成员访问表达式中的 id-expression 是一个 qualified-id, 表示函数被调用。否则,其 对象表达式的动态类型中的 final overrider (10.3) 被调用;这种呼叫被称为 虚函数调用。

    【讨论】:

    • @LiuNick Stack Overflow 说“谢谢”的方式是accept the answer which solved the problem(每个问题最多接受一个答案)。这将问题标记为已解决,并为回答者和您提供一些声誉。
    猜你喜欢
    • 2017-07-04
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多