C as an object oriented language

There is the GObject library:

The GLib Object System, or GObject, is a free software library (covered by the LGPL) that provides a portable object system and transparent cross-language interoperability. GObject is designed for use both directly in C programs and through bindings to other languages.


The traditional solution is the function pointer struct. I emphasize traditional. I can tell you what sort of code I wrote in PL/I and C years ago, but I don't claim to speak for the state of the 'art' if you can call this art.

There are many variations on this, and the below is a bit of a compromise.

struct SortOfAnAbstractClass {
   int (*function1)(SortOfAnAbstractClass* this, int arg1, int arg2, char * arg3);
   void (*function2)(SortOfAnAbstractClass* this, char *arg);
};

struct SortOfDerived {
   struct SortOfAnAbstractClass base;
   int instanceVariable1;
};

SortOfAnAbstractClass getMeOne() {
     SortOfDerived *d = malloc(sizeof SortOfDerived);
     memset(d, 0, sizeof SortOfDerived);
     d->function1 = myf1;
     d->function2 = myf2;
     return &d->base;
};

and then 'myf1' and 'myf2' cast their 'this' parameters and go to town. You can extend this to look ever more like a full virtual dispatch.

Another common variation from the mists of time:

struct SortOfAClass {
   void *creatorInfo;
   int (*function1)(SortOfAnAbstractClass* this, int arg1, int arg2, char * arg3);
   void (*function2)(SortOfAnAbstractClass* this, char *arg);
};

In this variation, there's no inheritance by inclusion. The derived classes each put their private state into their own object in creatorInfo.


Take a look at the GObject library: http://library.gnome.org/devel/gobject/2.22/.


You can implement polymorphism with regular functions and virtual tables (vtables). Here's a pretty neat system that I invented (based on C++) for a programming exercise: alt text
(source: goblin.tkk.fi)

The constructors allocate memory and then call the class' init function where the memory is initialized. Each init function should also contain a static vtable struct that contains the virtual function pointers (NULL for pure virtual). Derived class init functions call the superclass init function before doing anything else.

A very nice API can be created by implementing the virtual function wrappers (not to be confused with the functions pointed to by the vtables) as follows (add static inline in front of it, if you do this in the header):

int playerGuess(Player* this) { return this->vtable->guess(this); }

Single inheritance can be done by abusing the binary layout of a struct: alt text
(source: goblin.tkk.fi)

Notice that multiple inheritance is messier as then you often need to adjust the pointer value when casting between types of the hierarchy.

Other type-specific data can be added to the virtual tables as well. Examples include runtime type info (e.g. type name as a string), linking to superclass vtable and the destructor chain. You probably want virtual destructors where derived class destructor demotes the object to its super class and then recursively calls the destructor of that and so on, until the base class destructor is reached and that finally frees the struct.

Tags:

C