diff --git a/interfaces.c b/interfaces.c new file mode 100644 index 0000000..b1a915a --- /dev/null +++ b/interfaces.c @@ -0,0 +1,70 @@ +#include +#include + +// Here's a basic interface for geometric shapes. +typedef struct { + double (*area)(void *); + double (*perim)(void *); +} geometry; + +// For our example we'll implement this interface on +// `rect` and `circle` types. +typedef struct { + double width, height; +} rect; + +typedef struct { + double radius; +} circle; + +// To implement an interface in C, we need to define functions +// that match the function pointers in the interface. +// Here we implement `geometry` on `rect`s. +double rect_area(void *r) { + rect *rect_ptr = (rect *)r; + return rect_ptr->width * rect_ptr->height; +} + +double rect_perim(void *r) { + rect *rect_ptr = (rect *)r; + return 2 * rect_ptr->width + 2 * rect_ptr->height; +} + +// The implementation for `circle`s. +double circle_area(void *c) { + circle *circle_ptr = (circle *)c; + return M_PI * circle_ptr->radius * circle_ptr->radius; +} + +double circle_perim(void *c) { + circle *circle_ptr = (circle *)c; + return 2 * M_PI * circle_ptr->radius; +} + +// If a variable has an interface type, then we can call +// methods that are in the named interface. Here's a +// generic `measure` function taking advantage of this +// to work on any `geometry`. +void measure(void *g, geometry *geom) { + printf("Area: %f\n", geom->area(g)); + printf("Perimeter: %f\n", geom->perim(g)); +} + +int main() { + rect r = {.width = 3, .height = 4}; + circle c = {.radius = 5}; + + // The `circle` and `rect` struct types both + // implement the `geometry` interface so we can use + // instances of these structs as arguments to `measure`. + geometry rect_geometry = {rect_area, rect_perim}; + geometry circle_geometry = {circle_area, circle_perim}; + + printf("Rectangle:\n"); + measure(&r, &rect_geometry); + + printf("\nCircle:\n"); + measure(&c, &circle_geometry); + + return 0; +}