Определение области действия при наследовании - C ++
Вопрос
Я читал FAQ по C ++ 0x от Страуструпа и застрял на этом коде.Рассмотрим следующий код
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 ++ описывает все эти правила определения области видимости?
Решение
Первый код работает так, как и должен работать c ++.
Разрешение перегрузки соответствует очень сложному набору правил.Из библии Страуструпа на c ++ 15.2.2 "Неоднозначности между функциями из разных базовых классов не разрешаются на основе типов аргументов".
Далее он объясняет использование слова "использование", как вы описали.
Это было дизайнерское решение в языке.
Я склонен следовать книге Страуструпа, а не стандарту, но я уверен, что это там есть.
[Править]
Вот оно (из стандарта):
Глава 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.member.lookup] . НТН
Первая версия кода должна действительно вызывать B :: f. Вы переопределяете символ " f " в структуре "B", поэтому скрывает исходный символ "f" из структуры " A " ;. Это не перегрузка, как может показаться.
Всякий раз, когда компилятор встречает b.f (), он выполняет поиск в " B " структура для символа "f". Он присутствует там, поэтому компилятор решает вызвать B :: f (int), преобразовав double в int. Он не видит необходимости сканировать родительский класс для более подходящей функции ...
Тем не менее, когда вы добавляете "используя A :: f", это является директивой объяснения, чтобы компилятор сканировал родительский класс на наличие символа "f". Теперь в классе B есть две перегруженные функции: для int и для double.
Я также считаю, что вы могли бы написать b.A :: f (), не используя " используя " директива в исходном примере ...