CSC/ECE 517 Fall 2010/ch2 5c gn

From Expertiza_Wiki
Jump to navigation Jump to search

Dynamic Dispatch

Introduction

The process of identifying which version of the function to call based on the runtime type of the reference being used to execute the function. Dynamic Dispatch generally happens in OOL. For example, we can have a super class which defines a particular function and then there is a subclass which defines the same function (called overriding). When a reference to the super class is used to execute that function, then which version of the function gets execute depends on the type, the reference points to at that time, instead of type of the reference. In literature it also given different names like Runtime Binding or Dynamic Polymorphism .

To further understand what Dynamic Dispatch is, consider the below example:

class Animal {
    public void walk() {
        System.out.println("Animal::walk");
    }
}
class Dog extends Animal {
    public void walk() {
        System.out.println("Dog::walk");
    }
}

class Cat extends Animal {
    public void walk() {
        System.out.println("Cat::walk");
    }
}
Animal a = new _______();
a.walk();

The compiler cannot decide which version of walk (Animal, Dog or Cat) during compile time. So the decision of which version of the walk function to call will be deferred till the runtime.

Why we need Dynamic Dispatch

Dynamic Dispatch is one of the inherent feature of an Object Oriented Languauge 1. In a reasonably large software based on a procedural language like C, you will come across a bunch of switch or if statement which decides which version of the function to call. Ofcourse Dynamic Dispatch can be simulated in a procedural language like C, but it involves dangerous pointer manipulation, which is usually done well by the Compilers in case of OOL like C++.

For example, consider a toll gate application which charges differently based on the car type like Sedan, SUV, Coupe etc., If we have to do this in a procedural language like C in which each classes of car represented by structure, we might have something like this.

float calculate_charge(void *car, int type)
{
  switch(type)
  {
    case SUV:
        return suv_charge(car);
    case SEDAN:
        return sedan_charge(car);
    case COUPE:
        return coupe_charge(car);
}

You can see that the code above will quickly becomes messy as we define new type of car. If we have done the same in an OOL language like Java the above statement could be replacement by a simple:

car.charge();

The function charge will be overridden in each of the subclasses (Sedan, Suv, and Coupe). From the above example it is very evident that why we need dynamic dispatch and it is obviously useful.

How Dynamic Dispatch works

Dynamic Dispatch working in Detail

class Cat
{
    public:
        void talk() 
        {
             cout << "Meow!!";
        }
}; 

class Dog
{
    public:
        void talk() 
        {
             cout << "Bark!!";
        }
};


struct Cat
{
    int __id__; // 0
    char name[10];
};

struct Dog
{
    int __id__; // 1
    char name[10];
};

void cat_talk()
{
    printf("meow!");    
}

void dog_talk()
{
    printf("Bark!!");
}

void talk(void *object)
{
    int id = *(int *)object;
    vtable[id](); 
}

void (*vtable[2]);
vtable[0] = cat_talk;
vtable[1] = dog_talk;

Cat *c = new Cat(); 

Cat *c = malloc(sizeof(cat));
c->__id__ = 0;

Performance Evaluation

Does Dynamic Dispatching hurts in today's power packed Computers?

Conclusion

Further Reading

References