#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 double (*area)(void *self, void *parent); VIRTUAL void (*draw)(void *self, void *parent); }; double 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; }; double shape_area(void *self, void *parent) { double area = 0; struct _shape *pthis = (struct _shape *)parent; area = pthis->vtb.area(self, NULL); return area; } void shape_draw(void *self, void *parent) { struct _shape *pthis = (struct _shape *)parent; pthis->vtb.draw(self, NULL); } PRIVATE double _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 = (double (*)(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); }; double rect_area(void *self, void *parent) { double area = 0; struct _rect *pthis = (struct _rect *)parent; area = pthis->shape->vtb.area(self, NULL); return area; } void rect_draw(void *self, void *parent) { struct _rect *pthis = (struct _rect *)parent; pthis->shape->vtb.draw(self, NULL); } double _rect_area(void *self, void *parent) { struct _rect *pthis = (struct _rect *)self; double area = pthis->width * pthis->height; printf("rect area = %0.2f\n", area); return area; } void _rect_draw(void *self, void *parent) { printf("rect draw\n"); } struct _rect *rect_new(double width, double height) { // super static struct _virtual_table vtb = { .area = (double (*)(void *self, void *parent))_rect_area, .draw = (void (*)(void *self, void *parent))_rect_draw, }; struct _shape *shape = shape_new(); if (shape == NULL) { return NULL; } shape->vtb = vtb; // self struct _rect *rect = calloc(1, sizeof(struct _rect)); if (rect == NULL) { return NULL; } rect->width = width; rect->height = height; // set parent rect->shape = shape; return rect; } struct _circle { int invalid; // super struct _shape *shape; // attribute double radius; // method // void (*area)(void *self); // void (*draw)(void *self); }; double circle_area(void *self, void *parent) { double area = 0; struct _circle *pthis = (struct _circle *)parent; area = pthis->shape->vtb.area(self, NULL); return area; } void circle_draw(void *self, void *parent) { struct _circle *pthis = (struct _circle *)parent; pthis->shape->vtb.draw(self, NULL); } double _circle_area(void *self, void *parent) { struct _circle *pthis = (struct _circle *)self; double area = 3.14 * pthis->radius * pthis->radius; printf("circle area = %0.2f\n", area); return area; } void _circle_draw(void *self, void *parent) { printf("circle draw\n"); } struct _circle *circle_new(double radius) { // super static struct _virtual_table vtb = { .area = (double (*)(void *self, void *parent))_circle_area, .draw = (void (*)(void *self, void *parent))_circle_draw, }; struct _shape *shape = shape_new(); if (shape == NULL) { return NULL; } shape->vtb = vtb; // self struct _circle *circle = calloc(1, sizeof(struct _circle)); if (circle == NULL) { return NULL; } circle->radius = radius; // set parent circle->shape = shape; return circle; } struct _copper_cash { struct _shape *shape; struct _rect *rect; struct _circle *circle; double price; }; double copper_cash_area(struct _copper_cash *self, void *parent) { // 如果用的继承,那么就不能直接调用父类的虚接口,实现自己。 // 因为父类虚接口,是自己实现的。这样相当于自己调用自己。导致卡死。 // double circle_area = self->circle->shape->vtb.area(self->circle, self->circle); // double rect_area = self->rect->shape->vtb.area(self->rect, self->rect); double circle_area = 3.14 * self->circle->radius * self->circle->radius; double rect_area = self->rect->width * self->rect->height; double area = circle_area - rect_area; printf("copper cash area = %0.2f\n", circle_area - rect_area); return area; } void copper_cash_draw(struct _copper_cash *self, void *parent) { printf("copper cash draw\n"); } struct _copper_cash *copper_cash_new(double width, double height, double radius) { // super static struct _virtual_table vtb = { .area = (double (*)(void *self, void *parent))copper_cash_area, .draw = (void (*)(void *self, void *parent))copper_cash_draw, }; struct _shape *shape = shape_new(); if (shape == NULL) { return NULL; } shape->vtb = vtb; struct _rect *rect = rect_new(width, height); if(rect == NULL) { return NULL; } rect->shape = shape; struct _circle *circle = circle_new(radius); if (circle == NULL) { return NULL; } circle->shape = shape; // self struct _copper_cash *cc = calloc(1, sizeof(struct _copper_cash)); if (cc == NULL) { return NULL; } cc->price = 100; // set parent cc->shape = shape; cc->rect = rect; cc->circle = circle; return cc; } 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("----- rect & circle -----\n"); shape_area(rect, rect->shape); shape_draw(rect, rect->shape); shape_area(circle, circle->shape); shape_draw(circle, circle->shape); printf("----- [2] rect & circle -----\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("----- [2] shape -----\n"); // struct _shape *shape = shape_new(); // shape_area(shape, shape); // shape_draw(shape, shape); printf("----- copper_cash -----\n"); struct _copper_cash *cc = copper_cash_new(2, 2, 4); shape_area(cc, cc->shape); shape_draw(cc, cc->shape); printf("----- [2] copper_cash -----\n"); rect_area(cc, cc->rect); rect_draw(cc, cc->rect); circle_area(cc, cc->circle); circle_draw(cc, cc->circle); return 0; }