【问题标题】:C++ method overloading: base and derived parametersC++ 方法重载:基参数和派生参数
【发布时间】:2014-06-01 12:34:47
【问题描述】:

在网上搜索后,我没有找到这个问题的答案:

我有这个重载方法:

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

我不明白我做错了什么。

【问题讨论】:

  • minimal extension of your code 表明您的声明不正确。发布您的实际代码。
  • 您的 UIScoreLabel.handleGameEvent 不会覆盖基类 UIWidget.handleGameEvent,因为它们采用不同的参数类型。您要么需要使 UIScoreLabel 将 UIWidget * 作为其参数(然后将覆盖基类)并使用 RTTI 检查其类型,要么在基类中重载两个参数列表并在继承类中派生。跨度>
  • @Dampsquid 谢谢你的回答。不过我不是很明白。您能否展示一个扩展我在下面给出的答案的代码示例?谢谢。

标签: c++ inheritance overloading


【解决方案1】:

这是因为 C++ 不支持双重分派。如果您将变量声明为 Base,它将被这样对待。将其类型更改为 Derived 后,编译器就能够获取其真实类型,然后调用正确的方法。

要解决此问题,您可能需要使用Visitor Pattern

this answer 对此进行了很好的讨论。

【讨论】:

    【解决方案2】:

    我实际上从你那里得到了相反的结果,使用更多 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(){
        m1(new Bar); // Calls m1(Foo*)
        m1((Foo*) new Bar); // Calls m1(Bar*)
    }
    

    输出:

    Bar is on dancing!
    Bar is on stage!
    

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

    【讨论】:

    • 这就是我想要实现的。我已经更新了我的问题。感谢您的帮助
    【解决方案3】:

    我设法通过更改此行来解决问题:

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

    注意:这实际上解决了问题,但解决方案并不优雅,因为我想要这样的东西:

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

    【讨论】:

    • 请出示您的实际代码,这是一个重现问题的最小可编译示例。只需删除与问题无关的所有内容。说出您正在使用的编译器也可能会有所帮助。
    【解决方案4】:

    在您的“最小可编译示例”中,handleGameEvent 未声明为虚拟的,因此重载将不适用。

    【讨论】:

    • 感谢您的回答,这是复制粘贴错误,它们在我的代码中是虚拟的。
    猜你喜欢
    • 2021-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    相关资源
    最近更新 更多