views:

169

answers:

2

I've got the following structure:

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
    /* ... */
};

When I'm trying to call Bar() on an object of type G<D> with a E*, I get the following compile-time error:

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

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

If I rename the declarations of (virtual) void Bar(F*), the code compiles fine and works as expected.

Usage:

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, What's wrong with multiple overloads of member functions taking different arguments?

2, Why can't the compiler tell the difference between them?

+3  A: 

From your code:

  • G extends D in G<D>
  • you call on Bar(E*) on G -> G does not have Bar method so look into base class
  • base class is D
  • D has Bar(F*) but no Bar(E*) --> struct E is different type from struct F so you get an error

To answer your question: E is not related type to F and compile can tell the difference that's why you're getting an error.

I'm not sure which Bar you add virtual but if the base class already declares Bar as virtual all the classes that extends it already have Bar virtual so it does not matter if you add the word (virtual) into extended classes.

It would help if you showed how you instantiate your object and how you call Bar(F*) on it. There are runtime decisions that depends on how you call method and what parameters you passing.

stefanB
If you override one version of base class's overloaded functions and didn't mean to hide the other, you should make everything visible with a using declaration.
UncleBens
added a usage example and fixed the mistake: E and F are not related types. to the logic: D is-a C, and C has Bar(E*). isn't that supposed to count? by not declaring Bar(E*) and Bar(F*) as virtual in C and D I only intended to indicate that their behavior won't be / is not to be further specialized. they're used via pointers to their superclass objects, so it will still remain a virtual call per se.
iCE-9
+3  A: 

Only the versions of Bar in the most-derived class containing an override of Bar will be considered for overload resolution unless you add in using declarations. If you try

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

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

then it should work.

Troubadour