Michael Marineau
Class inheritence in C
For a while now I have been slowly developing a touchscreen music player to replace the stereo in my car. Although that concept should be fairly simple the project has turned into a bit of a playground for learning how to implement an X toolkit using nothing but C, XCB, and Cairo. One of the more recent legs this project has grown is an object oriented system for C which supports class inheritance and method overriding for use in my toolkit.
At this point I've got it almost the way I like it. Defining a class in a header looks something like this:
CLASS(mtk_widget, mtk_object)
int x, y, w, h;
struct mtk_window *window;
struct mtk_widget *parent;
cairo_surface_t *surface;
METHODS(mtk_widget, mtk_object, int x, int y, int w, int h)
void (*init)(mtk_widget_t *this, mtk_widget_t* parent);
void (*draw)(mtk_widget_t *this); /* children must implement this */
void (*update)(mtk_widget_t *this);
void (*mouse_press)(mtk_widget_t *this, int x, int y);
void (*mouse_release)(mtk_widget_t *this, int x, int y);
void (*mouse_move)(mtk_widget_t *this, int x, int y);
void (*set_geometry)(mtk_widget_t *this, int x, int y, int w, int h);
void (*set_parent)(mtk_widget_t *this, mtk_widget_t *parent);
END
This defines a new class named mtk_widget based on the base class mtk_object. The extra arguments to the METHODS macro are additional arguments for the object constructor.
To actually implement the class the corresponding C file will have something like this:
/* more methods up here */
static void set_parent(mtk_widget_t *this, mtk_widget_t *parent)
{
this->parent = parent;
}
mtk_widget_t* mtk_widget_new(size_t size, int x, int y, int w, int h)
{
mtk_widget_t* this = mtk_widget(mtk_object_new(size));
SET_CLASS(this, mtk_widget);
this->x = x;
this->y = y;
this->w = w;
this->h = h;
return this;
}
METHOD_TABLE_INIT(mtk_widget, mtk_object)
METHOD(init);
METHOD(draw);
METHOD(set_geometry);
METHOD(set_parent);
METHOD_TABLE_END
Methods can (and probably should) be static functions. The METHOD_TABLE_INIT macro defines the function _mtk_widget_class_init() to fill up a hidden structure named _mtk_widget_class which is the class virtual method table. Each object then has a pointer tucked away inside to its class's method table (set by the SET_CLASS macro). One thing that is a bit clunky about this is that the program must somehow call _mtk_widget_class_init() before the class is ever used. I would like to be able to do away with that by using GCC's constructor function attribute so it magically runs before main(). However the class hierarchy must be initialized in order but a way to order the constructors was not added until GCC 4.3. I'm using 4.1 on my system so that feature will have to wait for now.
Actually using objects looks something like this:
int main (int argc, char *argv[])
{
mtk_window_t *window;
mtk_widget_t *widget;
mtk_init();
window = new(mtk_window,640, 480);
widget = mtk_widget(new(mtk_text, 0, 0, 640, 480, "WHEE"));
call(window, mtk_container, add_widget, widget);
mtk_main();
mtk_cleanup();
return 0;
}
Pretty strait forward, call() is a bit weird though. It takes the arguments (object, class name that defined the method, method name, method arguments). I would like to be able to get rid of the class argument somehow (it is used to cast object to the correct type) but I haven't come up with a solution yet. I have a similar clunkyness with my super() macro for calling a parent class's method when doing method overriding.
That's pretty much it. As with the rest of this project it is a good example of making things more complicated than they need to be but it was an interesting challenge to put together.
The code for the above macros and base class can be found in this header and c file.







