Подтвердить что ты не робот

Виртуальная функция, реализованная в базовом классе, не найдена компилятором

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

struct One {};

struct Two {};

struct Base
{
    virtual void func( One & );
    virtual void func( Two & ) = 0;
};

struct Derived : public Base
{
    virtual void func( Two & );
};

void Base::func( One & )
{}

void Derived::func( Two & )
{}

// elsewhere
void this_fails_to_compile()
{
    One one;
    Derived d;
    d.func( one );
}

Я использую Visual С++ 2008. Сообщение об ошибке:

ошибка C2664: "Производный:: func": невозможно преобразовать параметр 1 из "Один" в "Два и amp;"

Я бы подумал, что отправка на основе типа будет работать и вызовет определенную функцию базового класса. Если я добавлю Derived::func( One & ), он будет скомпилирован и будет вызван правильно, но в моей ситуации эта версия функции может быть выполнена в базовом классе, и обычно производные классы сами не должны реализовывать ее. В настоящее время я работаю над этим, поместив в базовый класс именованную не виртуальную функцию, которая перенаправляет вызов функции, вызывающей проблему:

// not virtual, although I don't think that matters
void Base::work_around( One & one )
{
    func( one );
}

Это работает, но явно меньше идеала.

Какое наследование и/или правило скрытия имени я здесь отсутствует?

4b9b3361

Ответ 1

Вы скрываете метод в производном классе. Простейшим решением является добавление объявления using в производный класс.

struct Derived : public Base
{
    using Base::func;
    virtual void func( Two & );
};

Проблема заключается в том, что когда компилятор пытается найти идентификатор func в вызове d.func(one), он должен сделать это от Derived вверх, но он остановится в первом контексте, где он найдет func идентификатор, который в этом случае равен Derived::func. Дальнейший поиск не выполняется, и компилятор видел только Derived::func( Two& ).

Добавляя директиву using Base::func;, когда компилятор видит определение Derived, он приносит все объявления Base::func в область видимости и обнаруживает, что существует Base::func( One & ), который не был переопределен в Derived.

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

Derived d;
Base & b = d;
b.func( one ); // ok even without the 'using Base::func;' directive

Ответ 2

Вы скрываете функцию func(One&) в Derived. Вы можете использовать полное имя:

d.Base::func( one );