rahman
rahman

Reputation: 4948

call of overloaded function -with inherited class as argument- is ambiguous

This title has been used many times but after searching around 5-6 examples, I couldn't find anything that matches my problem:

I have a simple inheritance practice.

Class A is a base class, classes B & C inherit from it:

class A {

};

class B : public A { public:    int i; };

class C : public A { public:    int j; };

And a class P containing overloaded functions like this:

class P
{
public:
    void change(B *b)
    {
        b->i =1;
    }

    void change(C *c)
    {
        c->j =1;
    }
};

And when I use the functions like the following:

int main()
{
    A *b = new B();
    A *c = new C();
    P p;
    p.change(b);
    p.change(c);
    return 0;
}

it gives an error saying:

inherit2.cpp: In function ‘int main()’:
inherit2.cpp:37:12: error: call of overloaded ‘change(A*&)’ is ambiguous
inherit2.cpp:37:12: note: candidates are:
inherit2.cpp:21:7: note: void P::change(B*) <near match>
inherit2.cpp:21:7: note:   no known conversion for argument 1 from ‘A*’ to ‘B*’
inherit2.cpp:26:7: note: void P::change(C*) <near match>
inherit2.cpp:26:7: note:   no known conversion for argument 1 from ‘A*’ to ‘C*’
inherit2.cpp:38:12: error: call of overloaded ‘change(A*&)’ is ambiguous
inherit2.cpp:38:12: note: candidates are:
inherit2.cpp:21:7: note: void P::change(B*) <near match>
inherit2.cpp:21:7: note:   no known conversion for argument 1 from ‘A*’ to ‘B*’
inherit2.cpp:26:7: note: void P::change(C*) <near match>
inherit2.cpp:26:7: note:   no known conversion for argument 1 from ‘A*’ to ‘C*’

I will appreciate if you please help me solve the problem. rahman

Upvotes: 0

Views: 1330

Answers (4)

SingerOfTheFall
SingerOfTheFall

Reputation: 29966

You could:

  • Use polymorphism by adding a virtual setter function for i and j:

    class A {
    public:
        virtual void set( int ) = 0;
    };
    
    class B : public A {
    public:
        void set( int value )
        {
            i = value;
        }
    
    private:
        int i;
    };
    
    class C : public A {
    public:
        void set( int value )
        {
            j = value;
        }
    
    private:
        int j;
    };
    
    class P
    {
    public:
        void change(A * obj)
        {
            obj->set(1);
        }
    };
    
    int main()
    {
        A *b = new B();
        A *c = new C();
        P p;
        p.change(b);
        p.change(c);
        return 0;
    }
    
  • Case the pointer before passing it:

     A *b = new B();
     A *c = new C();
     P p;
     p.change(static_cast<B*>(b));
     p.change(static_cast<C*>(c));
    
  • Place the variable into the base class (and get rid of two change() functions):

    class A {
    public:
        int i;
    };
    
    class B : public A {};
    
    class C : public A {};
    

Upvotes: 2

Alok Save
Alok Save

Reputation: 206508

Root Cause:

When you call change() the parameter you pass is of the type A *, there is no exact match for this function in class P. The compiler tries to find the best possible match and it has two choices:

void change(B *); 
void change(C *);

None of them is a best match because each requires conversion from A* to B* or C*. Not that your classes do not provide for this conversion function and hence compiler reports the error.

Resolution:

You tell the compiler exactly which version of the function to chose by using casting.

p.change(static_cast<B*>(b));  
p.change(static_cast<C*>(c)); 

In both of above cases you know the actual type of the object being pointed by A * and so you can use static_cast and guide the compiler to find the best match function.

Upvotes: 1

john
john

Reputation: 8027

Polymorphism is one answer

class A
{
public:
    virtual void set() = 0;
};


class B : public A
{
public:
    virtual void set() { i = 1; }
private:
    int i;
};

class C : public A
{
public:
    virtual void set() { j = 1; }
private:
    int j;
};

class P
{
public:
    void change(A *a)
    {
        a->set();
    }
};

int main()
{
    A *b = new B();
    A *c = new C();
    P p;
    p.change(b);
    p.change(c);
    return 0;
}

With polymorphism there is no need for multiple change methods.

Upvotes: 2

Mark Ingram
Mark Ingram

Reputation: 73605

I would tweak your class hierachy to use polymorphism:

class A
{
public:
    virtual void SetVariable(const int value) = 0;
};

class B : public A
{
public:
    virtual void SetVariable(const int value) override { i = value; }
    int i;
};

class C : public A
{
public:
    virtual void SetVariable(const int value) override { j = value; }
    int j;
};

class P
{
public:
    void change(A *a)
    {
        a->SetVariable(1);
    }
};

This way you can use pointers to the base class (A) without knowing which specific derived type they are.

Upvotes: 1

Related Questions