11

After searching around the web I did not manage to find an answer to this question:

I have this overloaded method:

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

In this case "Derived" is a subclass of "Base".
When I call:

foo(new Derived());

I notice that always the first overloaded method is called, while I would like to achieve the opposite result (call the method which takes a "Derived*" object as a parameter).

How to solve this? Thank you.

EDIT:

Ok, this is my actual situation:

I have an UIWidget and a UIScoreLabel class. UIScoreLabel derives from UIWidget. I also have a GameEvent class (Base) and a P1ScoreGameEvent class (Derived).

UIWidget:

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

UIScoreLabel:

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

This is the call:

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

Output:

ui_widget

I don't understand what I'm doing wrong.

Michele
  • 751
  • 1
  • 8
  • 16
  • 3
    A [minimal extension of your code](http://ideone.com/rRgt9o) shows that your claim is not true. Post your actual code. – Angew is no longer proud of SO Apr 17 '14 at 09:54
  • 3
    your UIScoreLabel.handleGameEvent does not override the base class UIWidget.handleGameEvent since they take different parameter types. You either need to make UIScoreLabel take a UIWidget * as its parameter ( which will then override the base class ) and use RTTI to check its type, or overload both parameter lists in the the base class and derive both in the inherited class. – Dampsquid Apr 17 '14 at 11:03
  • @Dampsquid Thank you for your answer. I did not understand it very well though. Could you please show a code example extending the answer I gave below? Thank you. – Michele Apr 17 '14 at 11:20

4 Answers4

5

I actually get the opposite result from you, with the method which takes the more Derived type taking precedence. In the demo code below, the method which takes "Derived" seems to be called by default. However, you can always force it with a pointer cast.

#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*)
}

Output:

Bar is on dancing!
Bar is on stage!

Note that it is bar's methods that are called both times (this is correct polymorphic behavior!), but it is a different method of bar called by each of the overloads, to disambiguate.

merlin2011
  • 71,677
  • 44
  • 195
  • 329
2

I managed to solve the problem by changing this line:

UIWidget* scoreLabel = new UIScoreLabel();

To

UIScoreLabel* scoreLabel = new UIScoreLabel();

However, even if this solves the problem, I would like to avoid using this "trick", since my code keeps a list of UIWidget* objects and calls the handleGameEvent() method on them. If someone is aware of any other solution, please share it.

EDIT:

minimal compilable example:

#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: This actually solves the problem, but the solution is not elegant because I want to have something like this:

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"
}
Michele
  • 751
  • 1
  • 8
  • 16
  • Please show your _actual code_, a minimal compilable example that reproduces the issue. Just rip out everything not relevant to the question. It might also help to say what compiler you're using. – Useless Apr 17 '14 at 10:51
2

This is because C++ does not support double dispatch. If you declare your variable as Base, it will be treated so. Once you changed its type to Derived, the compiler was able to get its real type and then call the correct method.

To solve this problem you may want to use a Visitor Pattern.

There's a nice discussion about this in this answer.

Ricardo Rocha
  • 14,612
  • 20
  • 74
  • 130
SeeEn
  • 41
  • 5
0

in your "minimal compilable example", handleGameEvent is not declared virtual, so overloading will not apply.

quantdev
  • 23,517
  • 5
  • 55
  • 88