PDA

View Full Version : Implementing interfaces in C




Cromulent
Jul 6, 2009, 10:30 PM
I've been trying to figure this out and was wondering if I could get some feedback from the community.

Say I have the following interface:

struct IBase
{
void * (*connect)(void *);
int (*disconnect)(void *);
} IBase;

then I inherit from it:

struct IDatabase
{
struct IBase *lpVtable;

void * (*add_user)(void *);
} IDatabase;

I can then implement the IDatabase interface by using:

struct IDatabase * new(void)
{
struct IDatabase *newStruct = malloc(sizeof(struct IDatabase));
if(newStruct == NULL)
{
// handle error
}
return newStruct;
}
Obviously I have missed out a couple of steps (notably linking the function pointers to the correct functions in the implementation file which have static scope).

I can then use it by doing:

struct IDatabase *db = new();

does this look like something that you would be willing to use code wise? Any thoughts?



GeeYouEye
Jul 7, 2009, 12:32 AM
Looks about right.

autorelease
Jul 7, 2009, 12:45 AM
This idea kind of works, but isn't as clean as it looks. Assuming you have your IDatabase object and now want to call a method, you can't do

db->connect(db);

because you have to explicitly perform the vtable lookup. Instead you'd have to do

db->lpVtable->connect(db);

which ruins the nice abstraction you've created. Explicitly passing a "this" pointer to every method is cumbersome as well. You'd need a macro like

#define CALL(obj,m,...) obj->lpVtable->m(obj,__VA_ARGS__)
CALL(db, connect)

at which point you're in the realm of ugliness. :p All the implementations of OO features in C I've seen use tons of horrible macros.

Also note the complete lack of type safety. You'll be casting all over the place just to get everything to compile.

Bottom line: things like this are cool exercises, but don't actually tack OO features onto C in practice, especially when others have to maintain your code. If you need C++ features, just use C++.

Cromulent
Jul 7, 2009, 04:44 AM
This idea kind of works, but isn't as clean as it looks. Assuming you have your IDatabase object and now want to call a method, you can't do

db->connect(db);

because you have to explicitly perform the vtable lookup. Instead you'd have to do

db->lpVtable->connect(db);

which ruins the nice abstraction you've created. Explicitly passing a "this" pointer to every method is cumbersome as well. You'd need a macro like

#define CALL(obj,m,...) obj->lpVtable->m(obj,__VA_ARGS__)
CALL(db, connect)

at which point you're in the realm of ugliness. :p All the implementations of OO features in C I've seen use tons of horrible macros.

Also note the complete lack of type safety. You'll be casting all over the place just to get everything to compile.

Bottom line: things like this are cool exercises, but don't actually tack OO features onto C in practice, especially when others have to maintain your code. If you need C++ features, just use C++.

Ah that is the fun bit.

I am currently reading Object Orientated Programming in ANSI C (http://www.cs.rit.edu/~ats/books/ooc.pdf) (for the second or third time) and it is actually starting to make quite a bit of sense. The author specifically mentions how to do dynamic type checking on void pointers as well as long as you keep the inheritance chain intact.

mslide
Jul 7, 2009, 07:45 AM
I agree with autorelease. Why use C for something it wasn't really designed for? If you want OO features, then use a language designed for it... C++... especially if there will be others who will have to maintain this code in the future (including yourself if you ever need to come back to it after not looking at it for a long time).

autorelease
Jul 7, 2009, 12:06 PM
Cromulent: If you're curious, you should look at the source code of an Objective-C runtime, like GNUstep's libobjc. Remember, Objective-C is also a hack of OO concepts onto C, with some added syntax to make things look nicer. (and dynamic typing, dynamic dispatch, etc.)

Cromulent
Jul 9, 2009, 08:08 AM
Cromulent: If you're curious, you should look at the source code of an Objective-C runtime, like GNUstep's libobjc. Remember, Objective-C is also a hack of OO concepts onto C, with some added syntax to make things look nicer. (and dynamic typing, dynamic dispatch, etc.)

That's a pretty good idea. I'd be interested to see how much is done using the preprocessor and how much is done as pure language extensions.

Edit: I also managed to fudge type safety with the use of Unions in the above code rather than having to rely on void pointers all the time.