Ответ 1
Проблема, с которой вы сталкиваетесь, связана с тем, как работает поиск имени на С++. В частности, при разрешении члена компилятор будет искать статический тип объекта, к которому обращается элемент. Если идентификатор найден в этом классе, то поиск завершается и (в случае функций-членов) начинается перегрузка. Если идентификатор не найден, он будет сканировать иерархию, класс за классом, пытаясь найти идентификатор на один уровень за раз.
В вашем конкретном случае у вас есть c->onFoo();
и c
имеет тип c
. Компилятор не видит объявления onFoo
в c
, поэтому он продолжает вверх в иерархии. Когда компилятор проверяет B
, он видит, что на этом уровне есть объявление void onFoo(int i)
, поэтому оно останавливает поиск и пытается перегрузить разрешение. В это время разрешение перегрузки выходит из строя из-за несогласованности аргументов.
Тот факт, что объявление void onFoo(int)
присутствует на уровне B
, приводит к скрытию остальной части перегрузок в любом базовом классе, поскольку это остановит поиск. Обратите внимание, что это проблема с неквалифицированным поиском, функция все еще существует и применима к объекту, но не будет найдена путем регулярного поиска (вы все равно можете назвать ее как c->A::onFoo()
).
Что касается того, как справляться со скрытием, самым простым способом является использование объявления using для приведения функций в область видимости:
class B : A {
public:
using A::onFoo; // All A::onFoo overloads are *considered* here
void onFoo( int );
};
Эффект объявления using
заключается в том, что при поиске класса B
при поиске идентификатора onFoo
компилятору также рекомендуется учитывать все перегрузки onFoo
в базовом классе, позволяя регулярный поиск, чтобы найти A::onFoo()
.