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) в динамическом типе выражения объекта; такой вызов называется вызовом виртуальной функции.