4

I'm aware that, because C isn't object oriented, the closest we can get to methods is using function pointers in a struct. This is just a thought exercise, but is it possible to have:

list.add(void* data)

without passing in the list itself as a parameter?

I know that:

list.add(list_t* list, void* data)

would be easy to implement, but is there any way, using whatever parts of C, to simulate a method in this way?

I recognize it's possible the answer is no, but please explain to me if you can! Thanks.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Migwell
  • 18,631
  • 21
  • 91
  • 160
  • A more C++/Java-like way to implement OO in C is to add in every object a pointer to a structure defining its class that is where the pointers go. – salva Jun 27 '13 at 08:35
  • You could get something syntactically close if your compiler supported nested functions. But syntactically only; it would still be horrible. – Morwenn Jun 27 '13 at 08:58
  • Your question is confused, because what you need is `ListClass.add(list, data)` or `list->class.add(list, data)` ... you don't want function pointers in every list node. – Jim Balter Jun 27 '13 at 09:10
  • Also related, possibly useful reading: [Can you write object oriented code in C?](http://stackoverflow.com/q/351733) – Cody Gray - on strike Jun 27 '13 at 23:50

4 Answers4

6

This is the prettiest syntax I got using variadic macros (C99):

#define call(obj, method, ...) ((obj).method(&(obj), __VA_ARGS__))

usage (click for ideone):

struct class {
    int a;
    int (*method)(struct class* this, int b, int c);
};

int code(struct class* this, int b, int c) {
    return this->a*b+c;
}

struct class constructor(int a) {
    struct class result = {a, code};
    return result;
}

#define call(obj, method, ...) ((obj).method(&(obj), __VA_ARGS__))

#include <stdio.h>
int main() {
    struct class obj = constructor(10);
    int result = call(obj, method, 2, 3);
    printf("%d\n", result);
    return 0;
}
Kos
  • 70,399
  • 25
  • 169
  • 233
  • Nice. I didn't know about variadic macros, hence my uglier (and as it turns out, incorrect) answer. Still I wouldn't do the `&(obj)` part in the macro, since it won't allow calling methods on pointers, and having objects dynamically allocated is a very common case in C. Maybe it would be better to have just `(obj)` and have the programmer write `call(&obj, ...)` manually when the object is on the stack. – Jakub Wasilewski Jun 27 '13 at 08:45
  • @JakubWasilewski: you call methods through pointers with `call(*ptr, method, args...)` – Chris Dodd Jun 28 '13 at 01:00
  • 1
    If you're going to have more than one method in a class, it makes sense to gather them into a vtable -- so it becomes `#define call(obj, method, ...) ((obj).vtab->method(&(obj), __VA_ARGS__))` and you define a single `struct class_vtable_t {...} class_vtable = {...}` object with the function pointers in it. – Chris Dodd Jun 28 '13 at 01:05
  • Variadic macros definitely seem to be on the right track, but I don't know if #defining a call() method is any better than just directly calling the function code(), without using the macro. Is there any way to use these macros to create the line 'int result = obj.method(2, 3);', which would be closer to real OO programming? – Migwell Jul 01 '13 at 16:34
  • @Miguel re why not call `code()` directly: Conceptually, `main` doesn't know _how_ a method "method" is implemented in "obj", it only knows its name ("method") and signature. Technically, this achieves *dynamic dispatch*. – Kos Aug 16 '13 at 10:17
  • @Miguel re syntax: I can't see that `call(obj, method, 2, 3)` is any different from `obj->method(2, 3)` apart from aesthetics. Objective-C goes even more weird than that and it's still no less OO. – Kos Aug 16 '13 at 10:18
2

Not only instance methods, but you can even have CLOS-style generic methods with the right library. Laurent Deniau's COS library (also see paper: [link]) provides a full OO system you can just #include and start using immediately; the method syntax is no heavier than any other function call.

It's apparently fast, too; the author claims to have gained a performance edge on similar code expressed in Objective-C (I'll take the claim itself with a pinch of salt, but even if they're comparable that's impressive).

Alex Celeste
  • 12,824
  • 10
  • 46
  • 89
1

To emulate OO method calls, you need objects with class or vtable pointers. If your list_t contains, say, a funcs member that points to a struct containing function pointers, one of which is add, then your usage would be

list->funcs->add(list, data)

which you could capture in a variadic macro:

#define OO(obj, func, ...) (obj)->funcs->func(obj, __VA_ARGS__)

OO(list, add, data);
Jim Balter
  • 16,163
  • 3
  • 43
  • 66
0

If you want something simple, you can implement struct member functions using the blocks language extension. Blogged here.

You can use blocks to lambda-capture the associated struct, simulating the this pointer.

There's no virtual dispatch with this approach, so it's up to you whether you consider these true objects.

Chris Barrett
  • 3,383
  • 17
  • 21