Very Simple, Minimalist Technique For OOP in C...

57 views
Skip to first unread message

Chris Thomasson

unread,
Jun 21, 2007, 5:30:54 AM6/21/07
to
Here is the example code:

- http://appcore.home.comcast.net/vzoom/example/interface.zip


which is an analog of the following technique:

- http://groups.google.com/group/comp.lang.c/msg/6cf857051ca4029b


It's definitely not full-blown OOP is any sense of the term, however imho, I
think it could be fairly useful in certain scenarios... Now, let me try to
briefly describe it:

The provided example shows how a minimalist abstract interface for a "shape"
object might look. It also includes an implementation of simple circle and
square objects that are compatible with the abstract shape interface. If you
want to try and add another shape to get a feel for how "cumbersome" the
interface method is, well, here is a quick example of that:


<pseudo-code for adding, lets say, a triangle>
__________________________

triangle.h
__________________
/* Put include guard here */

#include "ishape.h"

/* Return values that are non-zero indicate error's */

/* Create a new triangle */
extern int Triangle_Create(IShape_t* const, /* [triangle params] */);

triangle.c
__________________
#include "triangle.h"


typedef struct Triangle_s Triangle_t;

struct Triangle_s {
/* [triangle members] */
};


static int Triangle_IObject_Destroy(void* const);
static int Triangle_IObject_Status(void* const);
static int Triangle_IShape_Draw(void* const);


/* Triangle IShape Interface VTable */
static IShape_VTable_t const Triangle_IShape_VTable = {
Triangle_IObject_Destroy,
Triangle_IObject_Status,
Triangle_IShape_Draw
};


/* Triangle Interface Functions */
int
Triangle_Create(
IShape_t* const IThis,
/* [triangle params] */) {
Triangle_t* const This = malloc(sizeof(*This));
if (This) {
/* [init This triangle] */
IOBJECT_INIT(IThis, This, &Triangle_IShape_VTable);
return 0;
}
return -1;
}


/* Triangle IObject Interface Functions */
int
Triangle_IObject_Destroy(void* const ThisState) {
Triangle_t* const This = ThisState;
free(This);
return 0;
}


int
Triangle_IObject_Status(void* const ThisState) {
Triangle_t* const This = ThisState;
/* [determine This triangle state; this is optional] */
return 0;
}


/* Triangle IShape Interface Functions */
int
Triangle_IShape_Draw(void* const ThisState) {
Triangle_t* const This = ThisState;
/* [draw This triangle] */
return 0;
}
__________________________


IMHO, that should be "fairly" straight forward... Now, here is how you could
use your Triangle:
__________________________

#include "triangle.h"

int Example(void) {
IShape_t MyShape;

int rStatus = Triangle_Create(&MyShape, /* [triangle params] */);
if (! rStatus) {

rStatus = IShape_Draw(&MyShape);
if (rStatus) {

rStatus = IObject_Status(&MyShape);
}

rStatus = IObject_Destroy(&MyShape);
}

return rStatus;
}
__________________________


I was wondering if you have come across any superior methods for very basic
OOP in C?


Any thoughts? Is this method total crap?

;^)


Thanks.

Chris Thomasson

unread,
Jun 21, 2007, 5:33:13 AM6/21/07
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:h_GdnYjvyb3P2efb...@comcast.com...
[...]

> It's definitely not full-blown OOP is any sense of the term, however imho,
> I think it could be fairly useful in certain scenarios... Now, let me try
> to briefly describe it:

[...]

Actually, I think the example code should be fairly self-explanatory...


Chris Thomasson

unread,
Jun 21, 2007, 7:04:00 AM6/21/07
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:h_GdnYjvyb3P2efb...@comcast.com...
> Here is the example code:
>
> - http://appcore.home.comcast.net/vzoom/example/interface.zip
>
>
> which is an analog of the following technique:
>
> - http://groups.google.com/group/comp.lang.c/msg/6cf857051ca4029b
>
>
> It's definitely not full-blown OOP is any sense of the term, however imho,
> I think it could be fairly useful in certain scenarios...

[...]

I just remembered that a library called Nobel uses same basic technique:


You can create an abstract interface in C by declaring a vtable structure
and the interface structure self. First we setup a type for the VTable's
first parameter (e.g., 'this' in c++):
_______________
typedef void* IObject_This_t;
typedef IObject_This_t const VTable_This_t;
_______________


Now, lets say that our new interface will be for a thread/process
mutual-exclusion synchronization object. So, we need to declare the
following structs:
_______________
typedef struct IMutex_s IMutex_t;
typedef struct IMutex_VTable_s IMutex_VTable_t;
_______________

And then we define the struct for our mutex interface:
_______________
struct IMutex_s {
IObject_This_t This;
IMutex_VTable_t const *VTable;
};

/*Take note of the names of the members of IMutex_t: (This, VTable). Its
import that you keep the names you choose consistent because they are going
to be depended upon. More on that later.
*/
_______________


An abstract mutex interface needs at least the following abstract functions
(Destroy, Lock, Unlock), so we define the following vtable struct:
_______________
struct IMutex_VTable_s {
int (*fp_IObject_Destroy) (VTable_This_t);
int (*fp_Lock) (VTable_This_t);
int (*fp_Unlock) (VTable_This_t);

/*Take note of the names of the members of IMutex_VTable_t:
(fp_IObject_Destroy, fp_Lock, fp_Unlock). Its import that you keep the names
you choose consistent because they are going to be depended upon. More on
that later.
*/
};
_______________


Now, we need to define the abstract interface that makes use of all the
above. We start be defining a helper function and an abstract function that
can init/destroy any object:
_______________
#define IObject_Initialize(__IThis, __ThisPtr, __VTablePtr) \
(__IThis)->This = (__ThisPtr); \
(__IThis)->VTable = (__VTablePtr)

#define IObject_Destroy(__IThis) \
(__IThis)->VTable->fp_IObject_Destroy((__IThis)->This)
_______________

Now we define the abstract functions of IMutex_t:
_______________
#define IMutex_Lock(__IThis) \
(__IThis)->VTable->fp_Lock((__IThis)->This)

#define IMutex_Unlock(__IThis) \
(__IThis)->VTable->fp_Unlock((__IThis)->This)
_______________


Stick all the above in a header file called (imutex.h) or whatever and
that's it for the abstract interface part. Now you create an object that
makes use of the interface:


your_mutex.h
_______________
/* include guard */
#include "imutex.h"
extern int Your_Mutex_Create(IMutex_t* const);

your_mutex.c
_______________
#include "your_mutex.h"
#include <stdlib.h> /* malloc/free */


/* declare/define your mutexs impl struct */
typedef struct Your_Mutex_s Your_Mutex_t;
typedef Your_Mutex_t* const Your_Mutex_This_t;

struct Your_Mutex_s {
/* [impl specific mutex data] */
};


/* declare your mutexs interface functions */
static int Your_Mutex_IObject_Destroy(VTable_This_t);
static int Your_Mutex_Lock(VTable_This_t);
static int Your_Mutex_Unlock(VTable_This_t);


/* define your mutex interface vtable */
static IMutex_VTable_t const Your_Mutex_VTable = {
Your_Mutex_IObject_Destroy,
Your_Mutex_Lock,
Your_Mutex_Unlock
};


/* define mutex create function */
int Your_Mutex_Create(IMutex_t* const IThis) {
Your_Mutex_This_t This = malloc(sizeof(*This));
if (This) {
/* [init impl This specific mutex data] */

/* init the IThis interface */
IObject_Initialize(IThis, This, &Your_Mutex_VTable);
return 0;
}
return -1;
}


/* define mutex object destroy */
int Your_Mutex_IObject_Destroy(VTable_This_t ThisState) {
Your_Mutex_This_t This = ThisState;
/* [teardown impl This specific mutex data] */
free(This);
return -1;
}


/* define mutex interface */
int Your_Mutex_Lock(VTable_This_t ThisState) {
Your_Mutex_This_t This = ThisState;
/* [lock impl This specific mutex] */
return -1;
}


int Your_Mutex_Unlock(VTable_This_t ThisState) {
Your_Mutex_This_t This = ThisState;
/* [unlock impl This specific mutex] */
return -1;
}
_______________


That's it for the interface and impl... Now you can use it like:


_______________
#include "your_mutex.h"


int Locked_Callback(
IMutex_t* const IThis,
int (*fp_Callback) (void*, IMutex* const),
void *CallbackState) {

int rStatus = IMutex_Lock(IThis);
if (! rStatus) {

rStatus = fp_Callback(CallbackState, IThis);
if (! rStatus) {
rStatus = IMutex_Unlock(IThis);
}
}

return rStatus;
}

static IMutex_t The_Lock;


int Critical_Section(void *ThisState, IMutex_t* const Lock) {
/* [your in a critical-section locked by 'Lock'] */
return 0;
}


void Some_Threads(/* [...] */) {
/* [...] */
Locked_Callback(&The_Lock, Critical_Section, /* [ptr to state */);
}


int main(void) {
int rStatus = Your_Mutex_Create(&The_Lock);
if (! rStatus) {
/* [create Some_Threads] */
}
return rStatus ;
}
_______________

Well, barring any typos, that's about it. ;^)


Chris Thomasson

unread,
Jun 21, 2007, 9:17:16 AM6/21/07
to
> int main(void) {
> int rStatus = Your_Mutex_Create(&The_Lock);
> if (! rStatus) {
> /* [create Some_Threads] */

/* [join threads] */

rStatus = IObject_Destroy(&The_Lock);

> }
> return rStatus ;
> }
> _______________


EventHelix.com

unread,
Jun 21, 2007, 10:52:19 PM6/21/07
to
On Jun 21, 5:30 am, "Chris Thomasson" <cris...@comcast.net> wrote:
> Here is the example code:
>
> -http://appcore.home.comcast.net/vzoom/example/interface.zip

>
> which is an analog of the following technique:
>
> -http://groups.google.com/group/comp.lang.c/msg/6cf857051ca4029b

The following article also covers OO programming in C:
http://www.eventhelix.com/RealtimeMantra/basics/object_oriented_programming_in_c.htm

--
EventStudio 4.0 - http://www.EventHelix.com/EventStudio
Sequence Diagram based System Modeling Tool

Malcolm McLean

unread,
Jun 22, 2007, 1:37:20 AM6/22/07
to

"Chris Thomasson" <cri...@comcast.net> wrote in message
news:h_GdnYjvyb3P2efb...@comcast.com...
> I was wondering if you have come across any superior methods for very
> basic OOP in C?
>

typedef struct object
{
void *ptr;
void *(*query)(struct object *obj, char *interface);
void (*kill)(struct object *obj)
} OBJECT;

Every object you query for an interface. An example would be

typedef struct
{
double (*length)(OBJECT *obj);
int (*getpos)(OBJECT *obj, double t, double *x, double *y);
} LINE;

So we are passed a line

void drawline(OBJECT *obj)
{
LINE *line;
int len;
int i;

line = obj->query(obj, "line");
if(!line)
fprintf(stderr, "Must be passed a line\n"):
len = (int) line->length(obj) + 1;
for(i=0;i<len;i++)
{
line->getpos(obj, ((double)i)/len, &x, &y);
drawpixel(x, y);
}
}

However it really is a lot of trouble. The syntactical support isn't really
there, so code quickly becomes a complete mess.

--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

Barry Schwarz

unread,
Jun 22, 2007, 3:02:18 AM6/22/07
to
On Thu, 21 Jun 2007 19:52:19 -0700, "EventHelix.com"
<event...@gmail.com> wrote:


snip

>
>The following article also covers OO programming in C:
>http://www.eventhelix.com/RealtimeMantra/basics/object_oriented_programming_in_c.htm

Did you really need to quote 130+ lines just to provide a reference.


Remove del for email

Richard Bos

unread,
Jun 22, 2007, 6:39:10 AM6/22/07
to
Barry Schwarz <schw...@doezl.net> wrote:

> On Thu, 21 Jun 2007 19:52:19 -0700, "EventSpam.com"
> <even...@gmail.com> wrote:
>
> >The following article also covers OO programming in C:

> >http://www.eventspam.com/spam.htm


>
> Did you really need to quote 130+ lines just to provide a reference.

No; but did you really need to quote a known spammer without munging his
links?

Richard

Barry Schwarz

unread,
Jun 22, 2007, 3:02:07 PM6/22/07
to
On Fri, 22 Jun 2007 10:39:10 GMT, r...@hoekstra-uitgeverij.nl (Richard
Bos) wrote:


>
>No; but did you really need to quote a known spammer without munging his
>links?
>

He's not one of the spammers I recognized and the link actually
contained reasonable C code.


Remove del for email

Chris Thomasson

unread,
Jun 23, 2007, 10:46:15 PM6/23/07
to
"Malcolm McLean" <regn...@btinternet.com> wrote in message
news:kZGdnQrKOJa...@bt.com...

>
> "Chris Thomasson" <cri...@comcast.net> wrote in message
> news:h_GdnYjvyb3P2efb...@comcast.com...
>> I was wondering if you have come across any superior methods for very
>> basic OOP in C?
[...]

> However it really is a lot of trouble. The syntactical support isn't
> really there, so code quickly becomes a complete mess.

Yeah, that seems to attempt to support more OOP techniques than the
"minimalist" method posted, which only provides an abstract interface
technique.

Johan Bengtsson

unread,
Jun 24, 2007, 3:53:57 PM6/24/07
to

You are right, the syntactical support isn't really there, but it is
quite possible to do full OOP in C with virtual functions and
everything, and it isn't that hard to do really.
It is even possible to do it better than in C++ with respect to using an
object oriented plugin system, something not easily done in C++, at
least not if you are *not* interested in recompiling every plugin at any
change in some of the base classes. I do not know about C# or other
languages - it might be better solved there but C is somewhat easier
because everything becomes visible and that makes it easier to see the
limitations and understand what happens. (I have done two
implementations of plugin based object oriented systems, one in C++ and
later one in C, the one in C actually meets the specifications better
even if it is more lines of code to do the work).

Reply all
Reply to author
Forward
0 new messages