重载函数的调用 - 以继承的类作为参数 - 是模棱两可的



这个标题已经被使用了很多次,但在搜索了大约 5-6 个示例后,我找不到任何符合我的问题:

我有一个简单的继承实践。

类 A 是一个基类,类 BC 继承自它:

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

还有一个包含重载函数的 P 类,如下所示:

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

当我使用如下函数时:

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

它给出一个错误说:

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*’

如果您能帮我解决问题,我将不胜感激。Rahman

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;
}

使用多态性,不需要多种change方法。

你可以:

  • 通过为ij添加虚拟二传函数来使用多态性:

    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;
    }
    
  • 传递指针之前将其大小写:

     A *b = new B();
     A *c = new C();
     P p;
     p.change(static_cast<B*>(b));
     p.change(static_cast<C*>(c));
    
  • 将变量放入基类中(并删除两个change()函数):

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

我会调整你的类层次结构以使用多态性:

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);
    }
};

这样,您可以使用指向基类(A)的指针,而不知道它们是哪个特定的派生类型。

根本原因:

当你调用change()你传递的参数是类型A *时,这个函数在类P中没有完全匹配。编译器尝试找到最佳匹配项,它有两个选择:

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

它们都不是最佳匹配,因为每个都需要从 A* 转换为 B*C* .并不是说您的类不提供此转换函数,因此编译器会报告错误。

分辨率:

通过使用强制转换,准确告诉编译器要选择哪个版本的函数。

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

在上述两种情况下,您都知道A *所指向的对象的实际类型,因此您可以使用static_cast并指导编译器找到最佳匹配函数。

相关内容

最新更新