Polymorphism via Function pointers
Function pointers in C provide a method to achieve polymorphism. In fact, they are one of the ingredients in the C++ object model as well.
See here for a quick refresher on C function pointers.
What we need is 'a function to fire the guns one by one'. Here's an outline of such a function:
void synchronized_fire(/*accept array of guns here*/) {
//iterate through the array
//and fire each element in there
}
What we've done is to remove the logic of 'which gun' and 'how to fire' from this function. Where do we put that logic? Let's try a struct:
struct Gun
{
int gun_id;
void (*fire)(int);
}
Observe that this struct has two members. One is a noun (the gun identification) and another is a verb (the activity of firing).
Then the function to fire them all would look like this. Remember that an array in C always needs to be accompanied by its bounds:
void synchronized_fire(struct Gun[] guns, unsigned int n_guns) {
for(int i = 0; i < n_guns; i++) {
guns[i].fire(guns[i].gun_id);
}
}
You can see that this function now doesn't care about the types of guns, as long as the structure is constructed properly.
How about functions to fire them in alternation?
void fire_alternate(struct Gun[] guns, unsigned int n_guns, int start_index) {
for(int i = start_index; i < n_guns; i += 2) {
guns[i].fire(guns[i].gun_id);
}
}
To fire even guns, call:
fire_alternate(guns, n_guns, 0);
To fire the odd ones, call:
fire_alternate(guns, n_guns, 1);
None of these functions need to be re-written when we replace a gun with a new type.
That is the strength of polymorphism! It comes from the ability of the 'fire' function-pointer to point to different functions in different structures - it takes on 'different forms' in different contexts.
To complete the story: All this is fine only if the struct-array is filled properly, correct? That's right! Here's one way to construct the array. Let's say we have a configuration of guns as in the previous post: howitzer_v1, dhanush, bofors_v2, howitzer_v2, dhanush
Click here to power back
struct Gun guns[] = {
{ .gun_id = GUN_ID1, .fire = howitzer_v1_fire },
{ .gun_id = GUN_ID2, .fire = dhanush_fire },
{ .gun_id = GUN_ID3, .fire = bofors_v2_fire },
{ .gun_id = GUN_ID4, .fire = howitzer_v2_fire },
{ .gun_id = GUN_ID5, .fire = dhanush_fire }
};
This is a structure-array initializer written as per the C99 standard. It's ok if you don't recognize the syntax. The important point is that the type and IDs of the guns need to be known at initialization time.
What did we achieve? We've isolated the impact of adding a new type of gun to the initialization part of the program, leaving all other functions untouched.
That's a great way to separate concerns, which is vital in large projects with many development teams.
Can we take it further? Is there a way to make the initialization code also unchanged, when a new type of gun is added? Can we include the new type of gun by just adding its fire function and specifying the gun-sequence in a data-file?
Feel free to express in any language of your choice, you don't need to restrict to C!What did we achieve? We've isolated the impact of adding a new type of gun to the initialization part of the program, leaving all other functions untouched.
That's a great way to separate concerns, which is vital in large projects with many development teams.
Can we take it further? Is there a way to make the initialization code also unchanged, when a new type of gun is added? Can we include the new type of gun by just adding its fire function and specifying the gun-sequence in a data-file?
Click here to power back
Comments
Post a Comment