Функция с тем же именем, но другой подписью в производном классе - PullRequest
81 голосов
/ 04 января 2009

У меня есть функция с тем же именем, но с разными сигнатурами в базовых и производных классах. Когда я пытаюсь использовать функцию базового класса в другом классе, который наследуется от производного, я получаю сообщение об ошибке. Смотрите следующий код:

class A
{
    public:
    void foo(string s){};
};

class B : public A
{
    public:
    int foo(int i){};
};

class C : public B
{
    public:
    void bar()
    {
        string s;
        foo(s);
    }
};

Я получаю следующую ошибку от компилятора gcc:

In member function `void C::bar()': no matching function for call to `C::foo(std::string&)' candidates are: int B::foo(int)

Если я удаляю int foo(int i){}; из класса B или переименовываю его из foo1, все работает нормально.

В чем проблема с этим?

Ответы [ 2 ]

101 голосов
/ 04 января 2009

Это потому, что поиск имени останавливается, если он находит имя в одной из ваших баз. Это не будет смотреться дальше в других базах. Функция в B shadows функция в 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-декларация считается от каждого подобъекта C, который имеет тип, содержащий декларацию ция, обозначенная использованием-декларации.96) Если результирующий набор объявлений не все из подобъектов того же типа, или набор имеет нестатический член и включает в себя элементы из различных подобъектов, есть двусмысленность и программа плохо сформирована. В противном случае этот набор является результатом поиска.

В другом месте (чуть выше) сказано следующее:

Для id-выражения [ что-то вроде "foo" ] поиск имени начинается в области видимости этого класса; для квалифицированного идентификатора [ что-то вроде «A :: foo», A является спецификатором вложенного имени ], поиск имени начинается в области спецификатора вложенного имени. Поиск имени происходит перед контролем доступа (3.4, пункт 11).

([...] поставлено мной). Обратите внимание, что это означает, что даже если ваш foo в B является приватным, foo в A все равно не будет найден (потому что контроль доступа происходит позже).

71 голосов
/ 04 января 2009

Функции в производных классах, которые не переопределяют функции в базовых классах, но которые имеют то же имя, будут скрывать другие функции с тем же именем в базовом классе.

Обычно считается плохой практикой иметь функции в производных классах, которые имеют то же имя, что и функции в классе баса, которые не предназначены для переопределения функций базового класса, поскольку то, что вы видите, обычно нежелательно. Обычно предпочтительно давать разные функции разным именам.

Если вам нужно вызвать базовую функцию, вам нужно будет охватить вызов с помощью A::foo(s). Обратите внимание, что это также отключило бы любой механизм виртуальных функций для A::foo(string) одновременно.

...