Виртуальная функция, реализованная в базовом классе, не найдена компилятором - PullRequest
17 голосов
/ 09 сентября 2010

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

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 C ++ 2008. Сообщение об ошибке:

ошибка C2664: 'Derived :: func': невозможно преобразовать параметр 1 из 'One' в 'Two &'

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

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

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

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

Ответы [ 2 ]

18 голосов
/ 09 сентября 2010

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

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
3 голосов
/ 09 сентября 2010

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

d.Base::func( one );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...