Виртуальная функция, реализованная в базовом классе, не найдена компилятором
У меня сложилась ситуация, когда компилятор не находит определение базового класса/реализацию виртуальной функции с тем же именем, что и другая функция-член.
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 );
}
Это работает, но явно меньше идеала.
Какое наследование и/или правило скрытия имени я здесь отсутствует?
Ответы
Ответ 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 );