Question

I thought that types would automatically resolve to the deepest part of the hierarchy they could. If Cat : Animal and you call cat->talk(), if Cat overrides a talk() from class Animal, the cat will say "meow", not some weird general Animal grumbling provided in base class Animal.

So I'm confused about this:

struct Animal
{
  virtual void talkTo( Animal* o ) {
    puts( "Animal-Animal" ) ;
  }
} ;

struct Cat : public Animal
{
  virtual void talkTo( Animal* o ) {
    puts( "Cat-Animal" ) ;
  }
  virtual void talkTo( Cat* o ) {
    puts( "Cat says meow to Cat" ) ;
  }
} ;

Here's some calling code:

  Cat *cat = new Cat() ;
  cat->talkTo( cat ) ; //Cat says meow to Cat

  Animal *animalCatPtr = cat ;      
  cat->talkTo( animalCatPtr ) ; //Cat-Animal

The last line here, where I send a Cat to cat->talkTo, but I'm using animalCatPtr. animalCatPtr still refers to a Cat, but yet its resolving to simply an Animal in the function call.

How can I make the pass pointer resolve to the deepest type in the hierarchy it really is? I don't want to do a series of dynamic_cast<> testing to see if the Animal I have on hand is really a Cat or Dog or what have you.

Was it helpful?

Solution 2

So you have to use "double dispatch" to achieve this. How crufty.

Basically, as the wikipedia link says,

The problem is that, while virtual functions are dispatched dynamically in C++, function overloading is done statically.

So, what you have to do is modify class Cat:

struct Cat : public Animal
{
  virtual void talkTo( Animal* o ) {
    //puts( "Cat-Animal" ) ;
    o->talkTo( this ) ; // TURN THE INVOKATION AROUND ("double dispatch")
  }
  virtual void talkTo( Cat* o ) {
    puts( "Cat says meow to Cat" ) ;
  }
} ;

Now, in

cat->talkTo( animalCatPtr ) ;

animalCatPtr is actually a Cat*. But the talkTo function doesn't know that, until we "turn around the invokation" in Cat::talkTo( Animal* ).

If animalCatPtr is actually only an Animal, then we will end up in base class Animal, invoking Animal::talkTo( Cat* ) if that is available, or Animal::talkTo( Animal* ) if only that function is available.

If animalCatPtr is actually a Cat, then we will end up invoking Cat::talkTo( Cat* ), which is the behavior we wanted.

OTHER TIPS

You want a form of double-dispatch, see http://en.wikipedia.org/wiki/Double_dispatch

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top