C++方法重载:基参数和导出参数

laximzn5  于 2023-04-08  发布在  其他
关注(0)|答案(4)|浏览(86)

我在网上搜索了一下,没有找到这个问题的答案:
我有一个重载的方法:

foo(Base* base);
foo(Derived* derived);

在这种情况下,“Derived”是“Base”的子类。
当我打电话:

foo(new Derived());

我注意到总是第一个重载的方法被调用,而我希望得到相反的结果(调用以“Derived*”对象作为参数的方法)。
如何解决这个问题?谢谢。
编辑:
好吧,这是我的实际情况:
我有一个UIWidget和一个UIScoreLabel类。UIScoreLabel从UIWidget派生。我还有一个GameEvent类(Base)和一个P1ScoreGameEvent类(Derived)。
UIWidget:

virtual void handleGameEvent(GameEvent* e) { printf("ui_widget"); }

UIScoreLabel:

virtual void handleGameEvent(P1ScoreGameEvent* e) { printf("ui_score_label"); }

这是我们的使命:

UIWidget* scoreLabel = new UIScoreLabel();
scoreLabel.handleGameEvent(new P1ScoreGameEvent());

输出:

ui_widget

我不明白我做错了什么。

myzjeezk

myzjeezk1#

这是因为C++不支持双重分派。如果你将变量声明为Base,它将被如此对待。一旦你将其类型更改为Derived,编译器就能够获取其真实的类型,然后调用正确的方法。
要解决这个问题,您可能需要使用Visitor Pattern
this answer中有一个很好的讨论。

wlwcrazw

wlwcrazw2#

在您“最小可编译示例”中,handleGameEvent没有声明为virtual,因此不会应用重载。

t9eec4r0

t9eec4r03#

实际上我从你那里得到了相反的结果,使用更Derived类型的方法优先。在下面的演示代码中,默认情况下似乎会调用使用“Derived”的方法。但是,您始终可以使用指针强制转换来强制调用它。

#include <stdio.h>
#include <iostream>

class Foo {
    public:
    virtual void perform() {
       printf("Foo is on stage!\n"); 
    }
   virtual void dance() {
       printf("Foo is on dancing!\n"); 
   }
};

class Bar : public Foo {
   public:
   void perform() {
       printf("Bar is on stage!\n"); 
   }
   void dance() {
       printf("Bar is on dancing!\n"); 
   }
};

int m1 (Foo *foo) {
    foo->perform();
}
int m1 (Bar *foo) {
    foo->dance();
}
int main(){
    Bar b;
    m1(&b); // Calls m1(Bar *)
    m1((Foo *) &b); // Calls m1(Foo *)
}

输出:

Bar is on dancing!
Bar is on stage!

请注意,两次调用的都是bar的方法(这是正确的多态行为!),但为了消除歧义,每一次重载都调用了bar的一个不同的方法。

e5njpo68

e5njpo684#

我通过改变这一行来解决这个问题:

UIWidget* scoreLabel = new UIScoreLabel();

UIScoreLabel* scoreLabel = new UIScoreLabel();

然而,即使这解决了问题,我也想避免使用这个“技巧”,因为我的代码保留了一个UIWidget* 对象的列表,并对它们调用handleGameEvent()方法。如果有人知道任何其他解决方案,请分享它。
编辑:
最小可编译示例:

#include <stdio.h>
#include <iostream>
#include <vector>

class GameEvent {};
class P1ScoreGameEvent : public GameEvent {};

class UIWidget { public: virtual void handleGameEvent(GameEvent* e) { printf("ui_widget"); } };
class UIScoreLabel : public UIWidget { public: virtual void handleGameEvent(P1ScoreGameEvent* e) { printf("ui_score_label"); } };

void main()
{
    UIWidget* w1 = new UIScoreLabel();
    w1->handleGameEvent(new P1ScoreGameEvent()); // output: "ui_widget"

    UIScoreLabel* w2 = new UIScoreLabel();
    w2->handleGameEvent(new P1ScoreGameEvent()); // output: "ui_score_label"
}

N.B:这实际上解决了问题,但解决方案并不优雅,因为我想有这样的东西:

void main()
{
    vector<UIWidget*> widgets;
    widgets.push_back(new UIScoreLabel());
    widgets.push_back(new UIScoreLabel());
    // push more..

    for (unsigned int = 0; i < widgets.size(); i++)
        widgets[i]->handleGameEvent(new P1ScoreGameEvent()); // output: "ui_widget", but I want "ui_score_label"
}

相关问题