2009-10-13 7 views
0

я получил следующую структуру:C++ проблема разрешения перегрузки

struct A 
{ 
    A(); 
    virtual ~A(); 

    virtual void Foo() =0; 
}; 

struct E; 
struct F; 

struct B: public A 
{ 
    B(); 
    virtual ~B(); 

    virtual void Bar(E*) =0; 
    virtual void Bar(F*) =0; 
}; 

struct C: public B 
{ 
    C(); 
    virtual ~C(); 

    void Bar(E*); 
}; 

struct D: public C 
{ 
    D(); 
    virtual ~D(); 

    void Foo(); 
    void Bar(F*); 
}; 

struct E: public A 
{ 
    E(); 
    virtual ~E(); 

    void Foo(); 
    /* ... */ 
}; 

struct F: public A 
{ 
    F(); 
    virtual ~F(); 

    void Foo(); 
    /* ... */ 
}; 

template <class _Base> 
struct G: public _Base 
{ 
    G(const _Base &b) 
    : _Base(b) 
    {} 

    virtual ~G() 
    {} 

    using _Base::Bar; // doesn't help 
    /* ... */ 
}; 

Когда я пытаюсь вызвать Bar() на объект типа G <D> с Е *, я получаю следующее ошибка времени компиляции:

error: no matching function for call to 'G<D>::Bar(E*&)'

note: candidates are: virtual void D::Bar(F*)

Если я переименовывать заявления (виртуальной) ничтожной Bar (F *), код компилируется нормально и работает, как ожидалось.

Использование:

typedef std::list<E*> EList; 
typedef std::list<F*> FList; 
EList es; 
FList fs; 

G<D> player(D()); 

es.push_back(new E); // times many 
fs.push_back(new F); // times many 

for(EList::iterator i0(es.begin()), i1(es.end()); i0 != i1; ++i0) 
{ 
    player.Bar(*i0); 
} 

for(FList::iterator i0(fs.begin()), i1(fs.end()); i0 != i1; ++i0) 
{ 
    player.Bar(*i0); 
} 

1, Что случилось с несколькими перегрузками функций-членов, принимающих различные аргументы?

2, Почему компилятор не может сказать разницу между ними?

+0

Оказывается, проблема связана с перегрузкой, а не с динамической диспетчеризацией. Я задал вопрос. Кроме того, вы нашли это: http://stackoverflow.com/questions/72010/c-overload-resolution – zyndor

ответ

3

Только версии Bar в самом производном классе, содержащие переопределение Bar, будут учитываться при разрешении перегрузки, если вы не добавите объявления using. Если вы попробуете

struct D:  public C 
{ 
    D(); 
    virtual ~D(); 

    void  Foo(); 
    void  Bar(F*); 
    using C::Bar; 
}; 

то он должен работать.

3

Из кода:

  • G расширяет D в G<D>
  • вы называете Bar(E*) на G ->G ли не Bar метод так смотреть в базу класса
  • базовый класс D
  • D имеет Bar(F*) но не Bar(E*) -> struct E не отличается тип от struct F так что вы получите ошибку

Чтобы ответить на ваш вопрос: E не имеет отношения типа к F и компилировать может сказать разницу, поэтому вы получаете ошибка.

Я не уверен, какой бар вы добавляете виртуальным, но если базовый класс уже объявляет Bar как виртуальный, все классы, которые его расширяют, уже имеют виртуальный бар, поэтому не имеет значения, добавите ли вы слово (виртуальное) в расширенные классы ,

Это поможет, если вы продемонстрируете, как вы создаете экземпляр объекта и как вы называете Bar (F *) на нем. Существуют решения времени выполнения, которые зависят от способа вызова метода и параметров, которые вы передаете.

+1

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

+0

добавил пример использования и исправил ошибку: E и F не относятся к типам. к логике: D is-a C, а C имеет Bar (E *). разве это не должно считаться?не объявляя Bar (E *) и Bar (F *) как виртуальные в C и D, я только хотел указать, что их поведение не будет/не должно быть дополнительно специализированным. они используются через указатели для своих объектов суперкласса, поэтому он по-прежнему останется виртуальным вызовом как таковым. – zyndor

Смежные вопросы