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

C

Chris Thomasson

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.
 
C

Chris Thomasson

[...]
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...
 
C

Chris Thomasson

Chris Thomasson said:
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. ;^)
 
C

Chris Thomasson

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

/* [join threads] */

rStatus = IObject_Destroy(&The_Lock);
 
E

EventHelix.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... 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.

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

Malcolm McLean

Chris Thomasson said:
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.
 
R

Richard Bos

Barry Schwarz said:
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
 
B

Barry Schwarz

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
 
C

Chris Thomasson

Malcolm McLean said:
Chris Thomasson said:
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.
 
J

Johan Bengtsson

Chris said:
Malcolm McLean said:
Chris Thomasson said:
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.

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).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top