#include #include #include /* Object Interface __________________________________________________*/ typedef void(*ct_iobject_fp_destroy) (void*); typedef void(*ct_iobject_fp_print) (void*, FILE*); struct ct_iobject_vtable { ct_iobject_fp_destroy fp_destroy; ct_iobject_fp_print fp_print; }; #define ct_iobject_vtable(mp_self) \ ((((struct ct_iobject_vtable*)(*((void**)(mp_self))))) #define ct_iobject_print(mp_self, mp_file) \ (ct_iobject_vtable(mp_self)->fp_print((mp_self), (mp_file)))) #define ct_iobject_destroy(mp_self) \ (ct_iobject_vtable(mp_self)->fp_destroy((mp_self)))) /* Person Interface __________________________________________________*/ typedef void(*ct_person_fp_talk) (void*, char const*, FILE*); struct ct_person_vtable { struct ct_iobject_vtable m_object; }; struct ct_person_prv_vtable { ct_person_fp_talk fp_talk; }; #define ct_iperson_talk(mp_self, mp_msg, mp_file) \ ((mp_self)->m_prv_vtable.fp_talk((mp_self), (mp_msg), (mp_file))) static void ct_person_print(void* raw_self, FILE* file); static void ct_person_talk(void* raw_self, char const* msg, FILE* file); static void ct_person_destroy(void* raw_self); static struct ct_person_vtable const g_ct_person_vtable = { { ct_person_destroy, ct_person_print } }; /* Person Impl __________________________________________________*/ struct ct_person { struct ct_person_vtable const* m_vtable; struct ct_person_prv_vtable m_prv_vtable; char* name; }; static int ct_person_create( struct ct_person* const self, char const* name ) { size_t name_size = strlen(name) + 1; self->name = calloc(1, name_size); if (self->name) { strcpy(self->name, name); // setup vtable self->m_vtable = &g_ct_person_vtable; self->m_prv_vtable.fp_talk = ct_person_talk; printf("(%p:ct_person_create):(name:%s)\n", (void*)self, self->name); return 0; } return -1; } static void ct_person_print( void* raw_self, FILE* file ) { struct ct_person* const self = raw_self; fprintf(file, "(%p:ct_person_print):(name:%s)\n", (void*)self, self->name); } static void ct_person_talk( void* raw_self, char const* msg, FILE* file ) { struct ct_person* const self = raw_self; fprintf(file, "(%p:ct_person_talk):(name:%s says %s)\n", (void*)self, self->name, msg); } static void ct_person_destroy( void* raw_self ) { struct ct_person* const self = raw_self; printf("(%p:ct_person_destroy):(name:%s)\n", (void*)self, self->name); free(self->name); } /* Employee Interface __________________________________________________*/ static void ct_employee_print(void* raw_self, FILE* file); static void ct_employee_destroy(void* raw_self); static struct ct_person_vtable const g_ct_employee_vtable = { { ct_employee_destroy, ct_employee_print } }; /* Employee Impl __________________________________________________*/ struct ct_employee { struct ct_person m_person; int id; }; static int ct_employee_create( struct ct_employee* const self, char const* name, int id ) { int status = ct_person_create(&self->m_person, name); if (!status) { // setup vtable self->m_person.m_vtable = &g_ct_employee_vtable; self->id = id; return 0; } return status; } static void ct_employee_print( void* raw_self, FILE* file ) { struct ct_employee* const self = raw_self; fprintf(file, "(%p:ct_employee_print):(id:%d)\n", (void*)self, self->id); // explicit chain ct_person_print(&self->m_person, file); } static void ct_employee_destroy( void* raw_self ) { struct ct_employee* const self = raw_self; printf("(%p:ct_employee_destroy):(id:%d)\n", (void*)self, self->id); // explicit chain ct_person_destroy(&self->m_person); } /* Testing 123... __________________________________________________*/ int main(void) { struct ct_employee employee; if (!ct_employee_create(&employee, "Chris M. Thomasson", 103)) { struct ct_person* const person = &employee.m_person; ct_iperson_talk(person, "Hello World!", stdout); ct_iobject_print(&employee, stdout); ct_iobject_destroy(person); } printf("\n_______________________________________\n"); if (!ct_employee_create(&employee, "Jane Doe", 1203)) { struct ct_person* const person = &employee.m_person; ct_iobject_print(person, stdout); ct_iperson_talk(person, "Goodbye", stdout); ct_iobject_destroy(&employee); } return 0; }