The approach I would recommend is to look at some other C code that uses a dispatch table and see how it's structured. Specific examples that I'm aware of off the top of my head (perhaps not the best teaching examples, since they're just random free software I've worked on) are MIT Kerberos and Heimdal, both of which use dispatch tables all over the place and the Apache web server and how it handles dynamically loaded modules. None of these do inheritance, but inheritance is relatively straightforward to add: you see if the method you're trying to call is NULL, and if so, you check the parent dispatch table for that method.
The short version for how to handle a dispatch table in C in general is that you define a data structure akin to the C++ vtable, which holds function pointers and some way of figuring out which pointer to use. Something like:
typedef void (*dispatch_func)(void *);
struct dispatch {
const char *command;
dispatch_func callback;
};
is the super-generic version, which maps string method names to functions that take a single anonymous pointer as an argument. Your actual dispatch table will be an array of these, like this (a modified example taken from tinyleaf in the INN source):
const struct dispatch commands[] = {
{ "help", command_help },
{ "ihave", command_ihave },
{ "quit", command_quit }
};
Obviously, the more you know about the functions, the more specific you can make the prototype, and you can embed other selection criteria (such as the number of arguments) into the dispatch table. (The actual INN source has minimum and maximum argument counts, passes in a structure of arguments instead of just a void *, and includes a command description in the dispatch table.)
The basic code to search a dispatch table is pretty simple. Assuming you have an array of those dispatch struct entries in vtable
and the length of the table in length
, something like:
for (i = 0; i < length; i++)
if (strcmp(command, vtable[i].command) == 0) {
(*vtable[i].callback)(data);
return;
}
To implement inheritance, you would need the parent pointer, and if you fall off the end of the loop, you move up to the parent and repeat the logic. (Obviously, this may be a useful place for a recursive function.)