#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, void *parent); VIRTUAL void (*draw)(void *self, void *parent); }; void virtual_area(void *self, void *parent) { ASSERT_CALL_VIRTUAL_METHOD(); } void virtual_draw(void *self, void *parent) { 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, void *parent) { struct _shape *pthis = (struct _shape *)parent; pthis->vtb.area(self, NULL); } void shape_draw(void *self, void *parent) { struct _shape *pthis = (struct _shape *)parent; pthis->vtb.draw(self, NULL); } PRIVATE void _shape_area(void *self, void *parent) { ASSERT_CALL_VIRTUAL_METHOD(); } PRIVATE void _shape_draw(void *self, void *parent) { 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, void *parent))_shape_area, .draw = (void (*)(void *self, void *parent))_shape_draw }; shape->vtb = vtb; return shape; } #if 0 void shape_free(struct _shape * self) { if (self != NULL) { free(self); } } #endif struct _rect { int invalid; // super struct _shape shape; // struct _shape; // struct _virtual_table vtb; // attribute double width, height; // method // void (*area)(void *self); // void (*draw)(void *self); }; void rect_area(struct _rect *self, void *parent) { printf("rect area = %0.2f\n", self->width * self->height); } void rect_draw(struct _rect *self, void *parent) { 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, void *parent))rect_area, .draw = (void (*)(void *self, void *parent))rect_draw }; rect->shape.vtb = vtb; // rect->vtb = vtb; return rect; } struct _circle { int invalid; // super struct _shape shape; // struct _shape; // struct _virtual_table vtb; // attribute double radius; // method // void (*area)(void *self); // void (*draw)(void *self); }; void circle_area(struct _circle *self, void *parent) { printf("circle area = %0.2f\n", 3.14 * self->radius * self->radius); } void circle_draw(struct _circle *self, void *parent) { 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, void *parent))circle_area, .draw = (void (*)(void *self, void *parent))circle_draw, }; // circle->vtb = vtb; circle->shape.vtb = vtb; return circle; } #if 0 struct _cube { // 继承自 struct _shape struct _rect; // attibute double length; }; void cube_area(struct _cube *self) { printf("cube area = %0.2f\n", self->length * self->length * self->length); } void cube_draw(struct _cube *self) { printf("cube draw\n"); } struct _cube* cube_new(double length) { struct _cube *cube = calloc(1, sizeof(struct _cube)); if (cube == NULL) { return NULL; } cube->length = length; static struct _virtual_table vtb = { .area = (void (*)(void *self))cube_area, .draw = (void (*)(void *self))cube_draw, }; cube->vtb = vtb; return cube; } #endif int main(int argc, char *argv[]) { struct _rect *rect = rect_new(4, 5); rect_area(rect, rect); rect_draw(rect, rect); struct _circle *circle = circle_new(3); circle_area(circle, circle); circle_draw(circle, circle); printf("------------------------------\n"); shape_area(rect, &rect->shape); shape_draw(rect, &rect->shape); shape_area(circle, &circle->shape); shape_draw(circle, &circle->shape); printf("------------------------------\n"); struct _rect *rect2 = (struct _rect *)rect_new(2, 3); shape_area(rect2, &rect2->shape); shape_draw(rect2, &rect2->shape); struct _circle *circle2 = (struct _circle *)circle_new(1); shape_area(circle2, &circle->shape); shape_draw(circle2, &circle->shape); printf("------------------------------\n"); struct _shape *shape = shape_new(); shape_area(shape, shape); shape_draw(shape, shape); return 0; }