Skip navigation

Ok, so say I have:

class Thing abstract
{
  
} ;

class Person : public Thing
{
  void MoveTo( Point p ) ;
} ;

class Building : public Thing
{
  // does NOT have MoveTo( Point p ) ;
} ;

I’m maintaining a vector<Thing*> to keep track of everything in the world.

When hittesting, a user might click on either a Building or a Person. Regardless, there’s a pointer stored to the currently selected Thing* in selectedThing.

Now, depending on what TYPE of thing is currently selected, the user can do different actions with that Thing. If the Thing* is really Person*, then a right-click somewhere on the map means one thing (i.e. move there) or for a building, a right click means (do nothign) or (set rally point).

So, if selectedThing is IN FACT a Person*, then we should call MoveTo() on the selectedThing (method exists!). But if selectedThing is NOT a person, then we should NOT call MoveTo() on it, because MoveTo() is not defined for a Building*.

What’s the best way to manage this problem?

1. typeid() reflection (which is bad because its implementation dependent and just _seems_ wrong?)
i.e. find if typeid() says selectedThing is Person* or Building*

if( typeid( selectedThing ) == classTypePerson ) 
{
  selectedThing->MoveTo( p ) ;
}
else
{
  // its not a person, so it can't move.
}

2. or maintaining separate vectors and going:

vector<Person*> people ;
vector<Building*> buildings ;

vector<Thing*> things ;

// FIND whether the selectedThing is in Person* vector or Building* vector.
for( int i = 0 ; i < people.size() ; i++ )
{
  if( people[i] == selectedThing )
  {
    // selected Thing is a person, so it can be cast
    // to Person* and MoveTo() can be executed on it
    dynamic_cast( selectedThing )->MoveTo( p ) ;
    break ;
  }
}

(( ANSWER: THE PROBLEM IS WRONG. class Thing should provide handles to “right click here” and “left click there” and the CONCRETE CLASSES should provide the implementation details. You’ve used inheritance incorrectly here and the Thing* interface DOESN’T HAVE ENOUGH METHODS if this is your problem.

So, the answer to this question is:

class Thing abstract
{
  virtual void MoveTo( Point p ) { /*do nothing by default*/ }
} ;

class Person : public Thing
{
  // actually move the person
  void MoveTo( Point p ) override ;
} ;

class Building : public Thing
{
  // does NOT (bother overriding) MoveTo( Point p ) ;
} ;

Then the code simply reduces to:

selectedThing->MoveTo( p ) ;

And so, IF the selectedThing is indeed a Building*, then selectedThing->MoveTo() boils down to (nothing happening), and if its a Person*, selectedThing->MoveTo() boils down to actual movement. Later you could build out the MoveTo command to MEAN SOMETHING ELSE to a Building, and this is EXACTLY what polymorphism is supposed to do: make different objects behave differently given the same command.

class Animal abstract { virtual void Speak() { } } ;

class Dog : public Animal {
  void Speak() { puts("Woof") ; } 
} ;

class Cat : public Animal {
  void Speak() { puts("Meow") ; } 
} ;
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: