//C has no interfaces: a table of pointers to functions plays one
typedef struct Shape Shape;
//the interface: what every shape can do
struct ShapeOps {
const char *name;
double (*area)(const Shape *self);
void (*scale)(Shape *self, double factor);
};
//an object keeps only a pointer to the table of its type:
//the table is one for all objects and never changes
struct Shape {
const struct ShapeOps *ops;
};
//the only implementation of the interface
typedef struct {
Shape base;
double width, height;
} Rect;
double rectArea(const Shape *self) {
const Rect *rect = (const Rect *)self;
return rect->width * rect->height;
}
void rectScale(Shape *self, double factor) {
Rect *rect = (Rect *)self;
rect->width *= factor;
rect->height *= factor;
}
const struct ShapeOps rectOps = {"rect", rectArea, rectScale};
Rect rect = {{&rectOps}, 2, 3};
//the code below sees only Shape and its table
Shape *shape = &rect.base;
double area1 = shape->ops->area(shape);
//area1 is 6
shape->ops->scale(shape, 2);
double area2 = shape->ops->area(shape);
//area2 is 24
const char *name = shape->ops->name;
//name is "rect"
//the table may grow, the object still holds one pointer
bool onePointer = sizeof(Shape) == sizeof(void *);
//onePointer is true
printf("area1 is %g\n", area1);
printf("area2 is %g\n", area2);
printf("name is %s\n", name);
printf("onePointer is %s\n", onePointer ? "true" : "false");