Це тому, що пошук імен зупиняється, якщо він знаходить ім’я в одній з ваших баз. Це не буде виглядати далі в інших базах. Функція в B затінює функцію в A. Ви повинні повторно оголосити функцію A в області B, щоб обидві функції були видимими всередині B і C:
class A
{
public:
void foo(string s){};
};
class B : public A
{
public:
int foo(int i){};
using A::foo;
};
class C : public B
{
public:
void bar()
{
string s;
foo(s);
}
};
Редагувати: Реальний опис, який надає Стандарт, є (з 10.2 / 2):
Наступні кроки визначають результат пошуку імен у діапазоні класу, C. Спочатку розглядається кожне оголошення для імені в класі та в кожному з його суб-об’єктів базового класу. Ім'я члена f в одному під-об'єкті B приховує ім'я члена f у під-об'єкті A, якщо A є суб-об'єктом базового класу B. Будь-які оголошення, які так приховані, вилучаються з розгляду. Кожне з цих оголошень, яке було введено за допомогою декларації using, вважається таким, що надходить від кожного під-об'єкта С, що має тип, що містить декларацію, позначену декларацією use.96) Якщо отриманий набір декларацій не є все з суб-об’єктів одного типу, або набір має нестатичний член і включає члени з різних суб-об’єктів, існує неоднозначність і програма неправильно сформована. В іншому випадку цей набір є результатом пошуку.
Він має сказати наступне в іншому місці (трохи вище нього):
Для виразу id [ щось на зразок "foo" ] пошук імен починається в області класу цього; для кваліфікованого ідентифікатора [ щось на зразок "A :: foo", A є вкладеним іменем-специфікатором ], пошук імен починається в області вкладеного імені-специфікатора. Пошук імен відбувається перед контролем доступу (3.4, пункт 11).
([...] поставлений мною). Зауважте, що це означає, що навіть якщо ваш foo в B приватний, foo в A все одно не буде знайдений (оскільки контроль доступу відбувається пізніше).