That depends on the exact “object-oriented” feature-set you want to have. If you need stuff like overloading and/or virtual methods, you probably need to include function pointers in structures:
typedef struct { float (*computeArea)(const ShapeClass *shape); } ShapeClass; float shape_computeArea(const ShapeClass *shape) { return shape->computeArea(shape); }
This would let you implement a class, by “inheriting” the base class, and implementing a suitable function:
typedef struct { ShapeClass shape; float width, height; } RectangleClass; static float rectangle_computeArea(const ShapeClass *shape) { const RectangleClass *rect = (const RectangleClass *) shape; return rect->width * rect->height; }
This of course requires you to also implement a constructor, that makes sure the function pointer is properly set up. Normally you’d dynamically allocate memory for the instance, but you can let the caller do that, too:
void rectangle_new(RectangleClass *rect) { rect->width = rect->height = 0.f; rect->shape.computeArea = rectangle_computeArea; }
If you want several different constructors, you will have to “decorate” the function names, you can’t have more than one rectangle_new()
function:
void rectangle_new_with_lengths(RectangleClass *rect, float width, float height) { rectangle_new(rect); rect->width = width; rect->height = height; }
Here’s a basic example showing usage:
int main(void) { RectangleClass r1; rectangle_new_with_lengths(&r1, 4.f, 5.f); printf("rectangle r1's area is %f units square\n", shape_computeArea(&r1)); return 0; }
I hope this gives you some ideas, at least. For a successful and rich object-oriented framework in C, look into glib’s GObject library.
Also note that there’s no explicit “class” being modelled above, each object has its own method pointers which is a bit more flexible than you’d typically find in C++. Also, it costs memory. You could get away from that by stuffing the method pointers in a class
structure, and invent a way for each object instance to reference a class.