[clug] Object-Oriented C?

David Gibson david at gibson.dropbear.id.au
Wed Feb 22 02:54:47 GMT 2006


On Wed, Feb 22, 2006 at 01:17:06PM +1100, Paul Wayper wrote:
> Hi all!
> 
> I wanted a set of C functions that could display and control a simple
> 'progress bar' on the (text) screen.  Because I couldn't see one already
> written, and because I've already implemented one in Perl, I wrote it
> again in C.  It's pretty simple but works nicely, and I'm still adding
> features to it.  Interested people can find it at
> http://biojanus.anu.edu.au/~paulway/progress.c and
> http://biojanus.anu.edu.au/~paulway/progress.h, or by doing svn checkout
> svn://tangram.dnsalias.net/pwlib-c/trunk (with a bunch of my other
> 'handy' routines).
> 
> Anyway, I've heard several people talk about writing C in an
> object-oriented way.  I've done the simplest thing here, which is that
> each function takes a PInfo pointer as its first argument, which is the
> 'object' that it operates on.  This isn't ver object-oriented at all, in
> that you have to constantly tell the 'method' which object to orient
> itself toward.  The more complex way would be to have a structure a bit
> like this:
> 
> typedef struct object_struct {
>     int public_property;
>     int (*method)(int value);
> } Object;
> 
> Thus if you had "Object *foo" you could call foo->method(42).  When you
> get a new object the 'constructor' would put the pointers to the actual
> methods into the Object struct so that the call was correct.  The
> problem is, of course, that the actual method function enters and sees -
> what?  No context, no object, no nothing.  Implicit in the 'constructor'
> of object-oriented actions is the idea that the method call gets told
> _which_ object it's operating on - Perl does it semi-explicitly by
> assuming that the first parameter is a reference to the object.
> 
> So how do I do this in C?  Is it even possible?  The only method I can
> think of involves some sort of trickery with knowing the address of the
> method function pointer and subtracting a known offset for each method
> that takes you back to the start of the actual object structure - in the
> same way that talloc puts its own information before the start of any
> pointer allocated by talloc.  But this still seems like opening the box
> with the crowbar inside.  Do I have to stick to the
> 'pseudo-object-oriented' approach?

There's nothing "pseudo" about your approach.  The object-orientation
is in how you organize your data and code with respect to each other,
not in the mere syntactic sugar of whether you need to explicitly pass
the "self" object to a method.  (Note for example that in Python, the
implementation of each method sees 'self' as an explicit, named,
parameter; instance.method(...) is exactly equivalent to explicitly
calling class.method(instance, ...) ).

Having the method pointers directly inside each instance is a bit
fiddly, though - it means you have a whole batch of things to
initialize in each new object instance.  The normal way around that is
to have something like:

struct object {
    struct object_ops *ops;
};

struct object_ops {
   int (*method1)(struct object *, int value);
   int (*method2)(struct object *, char *string);
};

Methods are then invoked as:
	obj->ops->methodXX(obj, ...);
Or, if you want some more syntactic sugar you can write a wrapper:
	int method1(struct object *obj, int value)
	{
		obj->ops->method1(obj, value);
	}
Or even:
	int method1(struct object *obj, int value)
	{
		if (obj->ops->method1)
			obj->ops->method1(obj, value);
		else
			/* default method... */	
	}

With this approach the 'ops' pointer encodes the dynamic part of the
object's type - it's pretty much directly equivalent to the virtual
method table pointer that C++ (say) would insert automatically.

This approach is used extensively in the kernel, similarly (with some
further extensions) in the Python interpreter and no doubt in many
other projects.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson


More information about the linux mailing list