Подтвердить что ты не робот

Использование-декларация в производном классе не скрывает ту же функцию, которая получена из базового класса

Посмотрите на следующий код:

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(), который доведен до C с помощью-объявления; если да, то почему c.C::f() все еще вызывает A::f()?

Если c.C::f() вызывает A::f(), это должно означать, что в области C, f() всегда следует ссылаться на A::f(), это функция объявления-объявления. Тогда почему в C::test() вызов f() по-прежнему вычисляется на B::f()?

4b9b3361

Ответ 1

Очень приятный вопрос, сложный случай поиска имени.

В принципе, когда имя f просматривается в области C, оно всегда находит 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 называется не виртуальным. Соответствующие правила следуют (цитируя С++ 14 окончательный проект N4140, акцент мой):

§10.3/15

Явная квалификация с оператором области (5.1) подавляет механизм виртуального вызова.

§5.2.2/1

... Если выбранная функция не виртуальна, или если id-выражение в выражении доступа к члену класса является квалифицированным id,, который вызывается этой функцией. В противном случае его конечный переопределитель (10.3) в динамическом типе выражения объекта; такой вызов называется вызов виртуальной функции.