Проблема разрешения перегрузки в C ++ - PullRequest
0 голосов
/ 14 октября 2009

У меня есть следующая структура:

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 с E *, я получаю следующую ошибку во время компиляции:

ошибка: нет соответствующей функции для вызова 'G :: Bar (E * &)'

примечание: кандидаты: виртуальная пустота D :: Bar (F *)

Если я переименую объявления (виртуального) void 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, почему компилятор не может определить разницу между ними?

Ответы [ 2 ]

3 голосов
/ 14 октября 2009

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

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

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

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

3 голосов
/ 14 октября 2009

Из вашего кода:

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

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

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

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

...