Dynamically submit in C using virtual method table

I hope to find a hint (preferably with a good example) for implementing dynamic dispatch in C.

I am learning C and how to practice, I want to translate from Java to C using the table of virtual dynamic distribution methods.

For example, I have Java code:

abstract class Foo { public abstract int val(); public abstract Boolean error(); } class Fail extends Foo { public int val(){ return 0;} public Boolean error(){return true;} } class IntFoo extends Foo { int v; public IntFoo(int value){this.value=v;} public int val(){ return v;} public Boolean error(){return False;} } 

and I could just translate some basic things like this:

 typedef struct Foo{ void(**vtable); }Foo; typedef struct Fail{ void(**vtable); struct Foo inherited; }Fail; typedef struct IntFoo{ void(**vtable); struct Foo inherited; }IntFoo; 

I'm stuck trying to complete this because I don't know:

  • How to define these methods in c.
  • Set the address of these methods in vtable so that the compiler recognizes the correct invocation method.
  • What else needs to be defined to make it work.
+7
source share
2 answers

There is no easy way to do this. However, you can manually do what the C ++ compiler does. In your case, it will look like this:

 typedef struct vtable_Fail { int (*val)(struct Fail *this_pointer); bool (*error)(struct Fail *this_pointer); } vtable_Fail; typedef struct vtable_IntFoo { int (*val)(struct IntFoo *this_pointer); bool (*error)(struct IntFoo *this_pointer); } vtable_IntFoo; int Fail_val(struct Fail *this_pointer) { return 0; } ... void IntFoo_ctor(struct IntFoo *this_pointer, int value) { this_pointer->v = value; } int IntFoo_val(struct IntFoo *this_pointer) { return this_pointer->v; } ... struct Fail { vtable_Fail *vtable; }; struct IntFoo { vtable_IntFoo *vtable; int v; }; 

The idea is that each structure should have an accompanying vtable structure that stores pointers to all virtual methods implemented by this structure. Vtable structures have only one instance each. They must be in static memory and should be used with pointers to functions. These pointers must implement virtual methods in a way that is necessary for each particular structure. Structures themselves can have many instances. The Vtable data parameters in the instance should point to the static vtable structure of their class.

The this_pointer parameter passes the address of the instance. It should be transmitted manually. This is C at the end of the day.

Note that you need to highlight vtable structures, init vtable pointers, etc. And you need to do it all manually using your own code.

+5
source

The approach I would recommend is to look at another C code that uses the dispatch table and see how it is structured. The specific examples that I know from my head (maybe not the best examples of training, as they are just the random free software that I worked on) are MIT Kerberos and Heimdal, both of which use sending tables all over the world and Apache web server and how it handles dynamically loaded modules. None of them inherit, but inheritance is relatively simple to add: you see if the method you are trying to call is NULL, and if so, you check the parent distribution table for this method.

The short version of how to handle the distribution table in C as a whole is that you define a data structure, akin to C ++ vtable, which contains pointers to functions and a way to determine which pointer to use. Something like:

 typedef void (*dispatch_func)(void *); struct dispatch { const char *command; dispatch_func callback; }; 

is a super-generic version that matches string label names for functions that take a single anonymous pointer as an argument. Your actual mailing table will be an array of such as this (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 functions, the more specific you can make a prototype, and you can embed other selection criteria (for example, the number of arguments) in the dispatch table. (The actual INN source has minimum and maximum argument values, passes the argument structure, not just void *, and includes a description of the command in the dispatch table.)

The basic code for finding a distribution table is pretty simple. Assuming you have an array of these distribution structure entries in vtable and the table length 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 will need a parent pointer, and if you fall from the end of the loop, you will go to the parent element and repeat the logic. (Obviously, this can be a useful place for a recursive function.)

+3
source

All Articles