The C programming language lends itself well to single inheritance object-oriented schemes, provided a little care is taken in the class structure.
Consider the following definition:
typedef struct _object {
int foo;
} Object;
typedef struct _thing {
Object o;
double bar;
} Thing;
Right here, I know the double declaration has lost half of you, and lost all the systems programmers… but bear with me. My background is in scientific computation, doubles are our bread and butter.
What is this “Object” at the at the head of “_thing”?
Well, Object is the parent of Thing. Object blocks out a contiguous chunk of memory at the head of the _thing struct. This let’s you do the following:
- Cast to Object and access the members of Object.
- Pass any child of Object through a function definition as an Object type.
What’s it look like?
Casting to parent in function call
Let’s write a little program, using the two structures above:
void
print_foo(Object * o) {
printf("o->foo: %dn", o->foo);
}
int
main (int argc, char ** argv) {
Thing t;
t.o.foo = 1;
printf("t.o.foo: %dn", t.o.foo);
print_foo(&t.o);
print_foo((Object *)&t);
return 0;
}
Assuming this little program is called “simple_inheritance.c,” compile with
gcc -DHAVE_CONFIG_H -I. -I.. -I../include -Wall -pedantic -g -O2 -MT simple_inheritance.o -MD -MP -MF .deps/simple_inheritance.Tpo -c -o simple_inheritance.o simple_inheritance.c
Running simple_inheritance produces
$ ./simple_inheritance t.o.foo: 1 o->foo: 1 o->foo: 1 $
Spiffy, no?
Ok, this is semi-cool, but that obnoxious cast on line 14 spoils some of the fun.
As it turns out, that cast is necessary to keep the compiler from squawking about potential type errors, but… and this is a very important but… our handy C Preprocessor (CPP) can make that sort of go away. That is, we can write a macro to hide that cast, then invoke the macro when we to use foo.
Now if you’re like me, you’re gonna be thinking something like “Who gives a rat’s patootie about foo? Why is that useful to me?”
Remember those typedefs, how we hid the implementation of structures?
We can do the same thing with functions by typedef’ing callbacks, then using those callbacks as elements in our spiffy Object struct. Recall prissy languages like Java usually have some sort of to_string() method sitting way back up the inheritance tree, usually at it’s root, not surprisingly, called “Object.”
By now you should correctly surmise this little series of articles on Object Oriented C is going somewhere. I won’t claim to know where it’s going (and wouldn’t say if I knew), but it’s on its way somewhere.
In fact, these articles are writing themselves, so let’s just follow along and see where we end up.