Правила областей видимости при наследовании - на C++
Я читал C++0x FAQ по Stroustrup и застрял с этим кодом. Рассмотрим следующий код
struct A
{
void f(double)
{
std::cout << "in double" << std::endl;
}
};
struct B : A
{
void f(int)
{
std::cout << "in int" << std::endl;
}
};
int main()
{
A a; a.f(10.10); // as expected, A.f will get called
B b; b.f(10.10); // This calls b.f and we lose the .10 here
return 0;
}
насколько я понимаю, когда тип наследуется, все защищенные и открытые члены будут доступны из производного класса. Но, согласно этому примеру, похоже, что я ошибаюсь. Я ожидал б.Ф вызовет базовые классы f. Я получил ожидаемый результат, изменив производный класс как
struct B : A
{
using A::f;
void f(int)
{
std::cout << "in int" << std::endl;
}
};
вопросы
- почему он не работал в первом коде?
- в каком разделе стандарта C++ описываются все эти правила области?
6 ответов
первый код работает как c++ предназначен для работы.
разрешение перегрузки следует очень сложному набору правил. Из Библии Строструпа на c++ 15.2.2 " [A]неоднозначности между функциями из разных базовых классов не разрешаются на основе типов аргументов."
Он продолжает объяснять использование "использования", как вы описали.
Это было дизайнерское решение в языке.
Я склонен следовать книге Страуструпа, а не стандартный, но я уверен, что он там.
[Edit]
вот он (из стандарта):
Глава 13
когда два или более различных объявления указаны для одного имени в той же области, это имя называется перегруженный.
и затем:
13.2 декларации соответствия
1 два объявления функции с тем же именем ссылаются на одну и ту же функцию, если они находятся в одной области и имеют эквивалент объявление параметра (13.1). Член функции производного класса не находится в той же области, что и член функции то же имя в базовом классе.
Это потому, что A::f "скрыт", а не "перегружен" или "переопределен". См.:
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9
В C++ нет перегрузки по областям, область в производных классах не является исключением. (в соответствии с языком программирования C++)
для получения дополнительной информации проверьтеhttp://www.research.att.com / ~bs / bs_faq2.html#overloadderived
в первом случае метод базового класса " f " равен скрытый методом производного класса. В C++ нет перегрузки по областям; вот почему он не вызывается. Стандарт C++ объясняет все правила поиска имени члена в раздел 10.2 поиск имени члена [class.член.lookup]. HTH
первая версия кода должна действительно вызывать B:: f. Вы повторно определяете символ " f "в структуре" B", поэтому он скрывает исходный символ" f "от структуры"A". Это не перегрузка, как может показаться.
всякий раз, когда компилятор встречает b.f (), он ищет в структуре "B" символ "f". Он присутствует там, поэтому компилятор решает вызвать B:: f(int), Преобразуя double в int. Он не видит необходимости сканировать родительский класс для более подходящей функции...
еще, когда вы добавляете " использование A:: f", это директива explict для компилятора для сканирования родительского класса для символа "f". Теперь класс B имеет две перегруженные функции: для int и для double.
Я также считаю, что вы могли бы написать b.A:: f() без использования директивы "using" в исходном примере...