tags:

views:

152

answers:

4
+2  Q: 

C++ design problem

I have a class hierarchy as such:

Entity  
    Stationary  
        Tree  
    Creature  
        Bear  
        Crow  

And I have a World and a Player. When the Player bumps into something it gets a call to handleCollision(Entity* entity) and then depending on what it is different things happen; if the player bumps into a tree nothing happens while the player attack if it's a bear. The problem is that I'm not sure how to differentiate between cases in a good way.

One thought that has come to mind is someting like this. Player::handleCollision(Entity*) calls Entity->handleCollisionHelper(Player& ). This is a virtual function which in Tree does nothing and in Creature(it should attack all creatures) calls Player.handleCollisionCreature(this) and then place the attack code in handleCollisionCreature. Is there a better way to do this without using RTTI (typeid etc)?

+3  A: 

The virtual method with (Player& player) arg seems perfectly good OO design. As you said, you could add some form of type or use RTTI and switch case through the permutations but that would be very C style functional style. Just as long as you aren't making thousands of virtual calls per second you should be fine.

ruibm
+3  A: 

Just to provide a reference for the official name - this problem is known as Double Dispatch (you need to decide what to do based on the type of two objects at the same time).

See the Wikipedia article http://en.wikipedia.org/wiki/Double_dispatch for some details, and a suggested solution.

Hexagon
Why does he need double dispatch. I only see one object that may have different types (the object being hit). On the other side the object doing the hitting is always a Player. Thus this is single dispatch as implemented via virtual functions.
Martin York
A: 

Instead of triggering on Entity*, why don't you have something like this:

 handleCollision(Stationary& stationary)
 {
     // Nothing to do yet?
 }

and

 handleCollision(Creature& creature)
 {
     creature.StartCombat(this);
 }

And remove the Entity* function. This will ensure only creatures will start combat (Add StartComabt function to your Creature class). Alternately, you could have a Combat class:

 handleCollision(Creature& creature)
 {
     Combat::Begin(this, creature);
 }
DanDan
A: 

I think what you're looking for is called "double dispatch" or "multimethods".

Calling different functions depending on the dynamic type of more than one object is not a built-in feature of C++, but there are a number of well-known techniques to roll your own. Cascaded calls as you propose is probably the most common one.

sbi