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

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

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()?

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

§10.3 / 15

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

§5.2.2 / 1

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

Другие вопросы по тегам