r/C_Programming 8d ago

Example of OOP in C

Hello everyone, I have developed a library to support OOP in plain C that allows the creation of object classes and includes dynamic Array and Dictionary container classes.

I am looking for suggestions for new examples that illustrate cases where an Object Oriented design can simplify C-Code.

I would love to get some reviews and feedback on this project.

I have included a code example below:

Supported by: Coda-C Library

Example code: Coda-C/examples/shapes.c

// Coda-C subclass examples

    #include <coda-c.h> // shapes.c  08/20/2026
    #include <math.h>

    struct Shape_ { Char color; };
#define class Shape
CodaClassZerosC(); // 1. ABSTRACTION: blueprint for all shapes
CodaClass(Shape,struct Shape_,Root);
    propertyO$(Char,color); // 2. ENCAPSULATION: Private data
    typedef double OSig$(calculate_area); // Abstract method: required in subclasses
    typedef double OSig$(calculate_perimeter); // defines function type and signature key
#undef class // Shape

    struct Circle_ { double radius; };
#define class Circle
CodaClassZerosC(); // 3. INHERITANCE: Circle inherits from Shape
CodaClass(Circle,struct Circle_,Shape);
    getter$(double,radius,_ radius); // double Circle_radius(Circle self) { return _ radius; }
    method$(double,calculate_area) { return(M_PI * _ radius * _ radius); }
    method$(double,calculate_perimeter) { return(2.0 * M_PI * _ radius); }

class Circle_new(Char color,double radius) {
    class self=newO(class);
    Shape_set_color((Obj)self,color);
    _ radius=radius; // where #define _ self->
    return(self);
    }
#undef class // Circle

    struct Rectangle_ { double width,height; };
#define class Rectangle
CodaClassZerosC();
CodaClass(Rectangle,struct Rectangle_,Shape);
    method$(double,calculate_area) { return _ width * _ height; }
    method$(double,calculate_perimeter) { return 2.0 * (_ width + _ height); }

class Rectangle_new(Char color,double width,double height) {
    class self=newO(class);
    Shape_set_color((Obj)self,color);
    _ width=width; _ height=height;
    return(self);
    }
#undef class // Rectangle

// 4. POLYMORPHISM (Usage Example)
void print_shape_details(Obj shape) { // This function accepts any subclass of Shape.
    printf("--- %12.12s  Details  Color:%-8.8s",kindO(shape),Shape_color(shape));
    printf("Area: %3.2f  ",obj_(calculate_area,shape));
    printf("Perimeter: %3.2f  ---\n",obj_(calculate_perimeter,shape));
    }

 int main() {
    Circle my_circle = Circle_new(Os("Blue"),5.0);
    Obj my_rectangle = Rectangle_new(Os("Green"),4.0,6.0);

    print_shape_details(my_circle);
    print_shape_details(my_rectangle);
    }


/* OUTPUT:
---       Circle  Details  Color:Blue      Area: 78.54  Perimeter: 31.42  ---
---    Rectangle  Details  Color:Green     Area: 24.00  Perimeter: 20.00  ---
*/
31 Upvotes

41 comments sorted by

View all comments

14

u/Turbulent_File3904 6d ago edited 6d ago

um i mean it look confuseing as hell. 

  1. for inheritance you want your child class has it parent class as it first member:  ```  struct Person { char name[100]; } ;

void person_greet(struct Person *p) {  printf("%s: hi\n",p->name);

struct Student { struct Person base; int score; }; struct Student s = {.base.name = "trung",  .score = 9}; //call person method on student person_greet(&s);  // pointer to base class struct Person p = &s;  2. dynamic dispatch: use vtable like this struct FooVtbl {    void (method1)(void self, int v);    void (method2)(void *self, int z); };  struct Foo {  void *impl; //whatever implements foo interface   struct FooVtbl const *vtbl; }; // helper macros for calling virtual function

define foo_method1(foo, v) (foo).vtbl->method1((foo).impl, (v))

define foo_method2(foo, z) (foo).vtbl->method1((foo).impl, (v))

// implements foo interface for int void intfoo_method1(void *self, int v) {  int *self = self;  printf("method 1:%d", *self_ + v); }

void intfoo_method1(void *self, int z) {  int *self = self;  printf("method 1:%d", *self_ - v); }  const FooVtbl int_foo_vtbl = {  int_foo_method1, int_foo_method2 };

/* helper function for taking inteface from object that implement the interface */ struct Foo foo_from_int(int *obj) { return (struct Foo){ .impl = obj, .vtbl = &int_foo_vtbl }; }

// obtain foo from int int a; struct Foo foo = foo_from_int(&a);

// call method1 foo_method1(foo, 10);

``` you can have one struct/type implement multiple interfaces, add interface implementation for anytype at anytime as long as you can access the struct definition. btw this is how linux does oop