Search code examples
c++design-patternsinheritancemultiple-dispatch

Special interaction between derived objects (i.e. mutiple dispatch)


So, I have a list of base class pointers:

list<Base*> stuff;

Then, at some point one of the objects will look through all other objects.

Base * obj = ...; // A pointer from the 'stuff'-list.
for (list<Base*>::iterator it = stuff.begin(); it != stuff.end(); it++)
{
    if (obj == *it)
        continue;

    // Problem scenario is here
   obj->interact(it);
}

What I want to achieve is that depending on what derived typeobj and *it are, they will interact differently with each other, i.e. DerivedA will destroy itself if it's interacting with DerivedB, but only if DerivedB has set the property bool c = true;. So something like:

struct Base 
{
    virtual void interact(Base * b); // is always called
};
struct DerivedA : public Base 
{
    virtual void interact(Base * b){} // is never called
    virtual void interact(DerivedB * b) // is never called
    {
        if (b->c)
            delete this;
    }
};
struct DerivedB : public Base 
{
    bool c = false;
    virtual void interact(Base * b){} // is never called
    virtual void interact(DerivedA * a) // is never called
    {
        c = true;
    }
};
// and many many more Derived classes with many many more specific behaviors.

At compile time, they are both Base-pointers and will not be able to call each other and expect the type to magically appear. If this was a one way relation, i.e. I knew what type of one of them, I could use the Visitor pattern. I believe I should use some kind of Mediator pattern but can't really figure out how since the mediator too will hold Base-pointers and thus it won't make a difference.

I haven't got a clue on how to continue... anyone?


Background:

I'm creating a game, this problem originates from the Room class who keeps track of it's contents, i.e. what GameObjects are currently in the room.

Sometimes, an object moves (for example, the player). The room will then loop over all objects that are on the soon-to-be-moved-upon floor tile (the loop above) and will check if the objects will interact with eachother.

For example, if it's a Troll the Player would want to hurt it. Or he would just like to hurt any Character (both Troll and Player are derived from Character) that originates from any another "team" (which can be accessed from the function getAlignment(), which all Characters implement).


Solution

  • If you can, grab a copy of "More Effective C++", and have a look at item #31 which is about implementing multiple dispatch, which is basically what you're looking for here. Meyers discusses several approaches to the problem and their various trade-offs. (He even uses a game as an example.)

    Perhaps the best advice he gives, however, is to try and redesign your code to avoid requiring this facility. In the text, a non-member function approach is also explored, which has the added bonus of eliminating the question of to which object each function describing an interaction should belong.