#include #include #include #include #include #define VIRTUAL #define PRIVATE static #define ASSERT_CALL_VIRTUAL_METHOD() assert(!("can't call abstract method")) struct _virtual_table { VIRTUAL void (*area)(void *self); VIRTUAL void (*draw)(void *self); }; void virtual_area(void *self) { ASSERT_CALL_VIRTUAL_METHOD(); } void virtual_draw(void *self) { ASSERT_CALL_VIRTUAL_METHOD(); } struct _virtual_table *virtual_new(void) { struct _virtual_table *vtb = calloc(1, sizeof(struct _virtual_table)); if (vtb == NULL) { return NULL; } vtb->area = virtual_area; vtb->draw = virtual_draw; return vtb; } struct _shape { struct _virtual_table *vtb; }; void shape_area(void *self) { struct _shape *pthis = (struct _shape *)self; pthis->vtb->area(self); } void shape_draw(void *self) { struct _shape *pthis = (struct _shape *)self; pthis->vtb->draw(self); } PRIVATE void _shape_area(void *self) { ASSERT_CALL_VIRTUAL_METHOD(); } PRIVATE void _shape_draw(void *self) { ASSERT_CALL_VIRTUAL_METHOD(); } struct _shape *shape_new(void) { struct _shape *shape = calloc(1, sizeof(struct _shape)); if(shape == NULL) { return NULL; } static struct _virtual_table vtb = { .area = (void (*)(void *self))_shape_area, .draw = (void (*)(void *self))_shape_draw }; shape->vtb = &vtb; return shape; } #define SUPER(self) (&(self)->shape) #if 0 void shape_free(struct _shape * self) { if (self != NULL) { free(self); } } #endif struct _rect { // super struct _shape shape; // attribute double width, height; // method // void (*area)(void *self); // void (*draw)(void *self); }; void rect_area(struct _rect *self) { printf("rect area = %0.2f\n", self->width * self->height); } void rect_draw(struct _rect *self) { printf("rect draw\n"); } struct _rect *rect_new(double width, double height) { struct _rect *rect = calloc(1, sizeof(struct _rect)); if (rect == NULL) { return NULL; } rect->width = width; rect->height = height; static struct _virtual_table vtb = { .area = (void (*)(void *self))rect_area, .draw = (void (*)(void *self))rect_draw }; SUPER(rect)->vtb = &vtb; return rect; } struct _circle { // super struct _shape shape; // attribute double radius; // method // void (*area)(void *self); // void (*draw)(void *self); }; void circle_area(struct _circle *self) { printf("circle area = %0.2f\n", 3.14 * self->radius * self->radius); } void circle_draw(struct _circle *self) { printf("circle draw\n"); } struct _circle *circle_new(double radius) { struct _circle *circle = calloc(1, sizeof(struct _circle)); if (circle == NULL) { return NULL; } circle->radius = radius; static struct _virtual_table vtb = { .area = (void (*)(void *self))circle_area, .draw = (void (*)(void *self))circle_draw, }; SUPER(circle)->vtb = &vtb; return circle; } int main(int argc, char *argv[]) { struct _rect *rect = rect_new(4, 5); rect_area(rect); rect_draw(rect); struct _circle *circle = circle_new(3); circle_area(circle); circle_draw(circle); printf("------------------------------\n"); shape_area(rect); shape_area(circle); shape_draw(rect); shape_draw(circle); printf("------------------------------\n"); struct _shape *shape = (struct _shape *)rect_new(2,3); shape_area(shape); shape_draw(shape); struct _shape *shape2 = NULL; shape2 = (struct _shape *)circle; shape_area(shape2); shape_draw(shape2); printf("------------------------------\n"); struct _shape *shape3 = shape_new(); shape_area(shape3); shape_draw(shape3); return 0; }