Правила областей видимости при наследовании - на 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;
    }
};

вопросы

  1. почему он не работал в первом коде?
  2. в каком разделе стандарта 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" в исходном примере...