I want to do some object-oriented style programming in C using polymorphism, where my interface class contains a pointer to a table of functions. Example something like:
/* Implement polymorphism in C, Linux kernel-style */
struct statement {
const struct statement_ops *ops;
struct list_head list; /* when on master input list */
void *private; /* pointer to type-specific data */
};
struct statement_ops {
int (*analyse)(void *private, int pc);
int (*get_binary_size)(void *private);
};
void user(void)
{
struct statement *s = make_a_statement();
if (s->ops->analyse(s->private, foo))
blah blah;
}
I’d like to be able to write something without explicitly passing s->private into every “method”. Any ideas? Some macro tricks maybe?
If this is part of the public interface, you can add accessor functions. A hidden benefit is that you can do sanity checks and other work in the accessor. (Note I called the “this” pointer “o”, as in “object”. I prefer it that way for consistency.)
You can now call this without the explicit passing of “private”.
While it may seem that this provides no benefit, because you still have to implement the accessors, assuming that you want a well defined and robust interface, the accessor functions are the only sane place to put the assertions and the interface documentation. In fact, if you write good assertions, the assertions themselves help document the interface. And once you add sanity checks in the accessors, you don’t have to add them in the actual methods they call.
Of course, this approach only makes sense when the function called via the function pointer will be something provided by the user, or in some other way can be different things. If there’s a single
analyse()method that will always do the same thing, you can simply implement astatement_analyse()that directly does what it needs to do.Small note: when doing OOP, I prefer to typedef the structs and give them CamelCase names. I use this convention as a way of telling that the struct is opaque and should only be accessed via its public interface. It also looks nicer, though that is subjective. I also prefer having the user allocate the memory for the struct itself, as opposed to the constructor malloc’ing it. That avoids having to handle malloc failure, and makes the program a little bit more efficient.