/**** public.h */
/*** Object types */
typedef struct s_animal_ s_animal;
typedef struct s_cat_ s_cat;
typedef struct s_dog_ s_dog;
/*** Function types */
typedef void f_any(void);
typedef f_any * f_handler(s_animal *, f_any op);
typedef void f_pet(s_animal *);
/*** Struct/union definitions */
struct s_animal_ {
s_animal * self;
f_handler * handler;
};
struct s_cat_ {
s_animal animal;
int lives;
const char * pet_noise;
};
struct s_dog_ {
s_animal animal;
const char * pet_noise;
};
/*** Function declarations */
extern f_pet pet;
extern s_cat * make_cat(void);
extern s_dog * make_dog(void);
/**** private.c */
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
/*** Function definitions */
void pet(s_animal * animal) {
f_any * pet_func = animal->handler(animal, (f_any *)pet);
f_pet * pet_func2;
if (pet_func == (f_any *)0) {
puts("Huh? (Type \"help\" for help.)");
return;
};
pet_func2 = (f_pet *)pet_func;
pet_func2(animal);
return;
}
static f_pet pet_cat;
static void pet_cat(s_animal * animal) {
s_cat * cat = (void *)animal;
puts(cat->pet_noise);
return;
}
static f_handler handle_cat;
static f_any * handle_cat(s_animal * animal, f_any * op) {
if (op == (f_any *)pet)
return (f_any *)pet_cat;
return (f_any *)0;
}
s_cat * make_cat(void) {
s_cat * cat = malloc(sizeof *cat);
if (!cat) return NULL;
cat->animal.self = &cat->animal;
cat->animal.handler = handle_cat;
cat->lives = 9;
cat->pet_noise = "Purr, purr...";
return cat;
}
static f_pet pet_dog;
static void pet_dog(s_animal * animal) {
s_dog * dog = (void *)animal;
puts(dog->pet_noise);
return;
}
static f_handler handle_dog;
static f_any * handle_dog(s_animal * animal, f_any * op) {
if (op == (f_any *)pet)
return (f_any *)pet_dog;
return (f_any *)0;
}
s_dog * make_dog(void) {
s_dog * dog = malloc(sizeof *dog);
if (!dog) return NULL;
dog->animal.self = &dog->animal;
dog->animal.handler = handle_dog;
dog->pet_noise = "Pant, pant...";
return dog;
}
/**** test.c */
#ifdef NORMALLY_THIS_WOULD_BE_INCLUDED
#include "public.h"
#endif
int main(void) {
s_cat * kitty = make_cat();
s_dog * doggy = make_dog();
if (kitty) {
pet(&kitty->animal);
free(kitty);
}
if (doggy) {
pet(&doggy->animal);
free(doggy);
}
return 0;
}