Created
February 17, 2018 05:08
-
-
Save tjhv/7a54aed6b90145485d004e0c5dc3e4a7 to your computer and use it in GitHub Desktop.
Mock inheritance in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <stddef.h> | |
typedef void * (* class_ctor_t)(void *); | |
typedef struct Class Class_t; | |
typedef struct ClassImpl | |
{ | |
size_t size; | |
uint8_t id; | |
char * name; | |
} ClassImpl_t; | |
typedef struct Class | |
{ | |
Class_t *_super; | |
Class_t *_sub; | |
ClassImpl_t impl; | |
class_ctor_t ctor; | |
} Class_t; | |
typedef enum EventType | |
{ | |
NOTIFY_EVENT = 0, | |
TOTAL_EVENTS | |
} EventType_t; | |
typedef struct Event | |
{ | |
EventType_t type; | |
char *desc; | |
} Event_t; | |
typedef struct Object Object_t; | |
void ObjectNotify(Object_t *, Event_t); | |
typedef void ((* object_notify_t)(Object_t *, Event_t)); | |
typedef void ((* handle_event_t) (void *, Event_t)); | |
typedef struct ObjectVtbl | |
{ | |
object_notify_t notify; | |
} ObjectVtbl_t; | |
ObjectVtbl_t objectVtbl_defaults = { | |
.notify = &ObjectNotify | |
}; | |
typedef struct Object | |
{ | |
Class_t *_base; | |
ObjectVtbl_t *_vptr; | |
handle_event_t HandleEvent; | |
} Object_t; | |
void HandleEvent(void *self, Event_t e) | |
{ | |
if(!self) return; | |
Object_t *obj = self; | |
if(!obj) printf("null object\n"); | |
if(!obj->_base) printf("null object base\n"); | |
printf("Handling event %s for %p \"%s\"\n", e.desc, obj, obj->_base->impl.name); | |
} | |
Class_t BaseClass = { | |
._super = NULL, | |
._sub = NULL, | |
.impl = { | |
.size = 48, | |
.id = 0, | |
.name = "BaseClass" | |
}, | |
.ctor = NULL | |
}; | |
void BaseObjectCtor(void *self) | |
{ | |
if(!self) return; | |
} | |
Object_t ObjectBase = { | |
._base = NULL, | |
._vptr = &objectVtbl_defaults, | |
.HandleEvent = &HandleEvent | |
}; | |
void * Class1Ctor(void *); | |
void * Class2Ctor(void *); | |
void * Class3Ctor(void *); | |
void * Class4Ctor(void *); | |
void * Class5Ctor(void *); | |
void ClassInfo(void *); | |
Class_t Class1 = { | |
._super = (Class_t *)&ObjectBase, | |
._sub = NULL, | |
.impl = { | |
.size = 128, | |
.id = 1, | |
.name = "Class1" | |
}, | |
.ctor = &Class1Ctor | |
}; | |
Class_t Class2 = { | |
._super = &Class1, | |
._sub = NULL, | |
.impl = { | |
.size = 256, | |
.id = 2, | |
.name = "Class2" | |
}, | |
.ctor = &Class2Ctor | |
}; | |
Class_t Class3 = { | |
._super = &Class2, | |
._sub = NULL, | |
.impl = { | |
.size = 128, | |
.id = 3, | |
.name = "Class3" | |
}, | |
.ctor = &Class3Ctor | |
}; | |
Class_t Class4 = { | |
._super = &Class3, | |
._sub = NULL, | |
.impl = { | |
.size = 122, | |
.id = 4, | |
.name = "Class4" | |
}, | |
.ctor = &Class4Ctor | |
}; | |
Class_t Class5 = { | |
._super = (Class_t *)&ObjectBase, | |
._sub = NULL, | |
.impl = { | |
.size = 108, | |
.id = 5, | |
.name = "Class5" | |
}, | |
.ctor = &Class5Ctor | |
}; | |
void * Class1Ctor(void *self) | |
{ | |
if(!self) return NULL; | |
Class_t *_class = (Class_t *)self; | |
printf("\n%s\n", __func__); | |
ClassInfo(self); | |
return self; | |
} | |
void * Class2Ctor(void *self) | |
{ | |
if(!self) return NULL; | |
Class_t *_class = (Class_t *)self; | |
printf("\n%s\n", __func__); | |
ClassInfo(self); | |
return self; | |
} | |
void * Class3Ctor(void *self) | |
{ | |
if(!self) return NULL; | |
Class_t *_class = (Class_t *)self; | |
printf("\n%s\n", __func__); | |
ClassInfo(self); | |
return self; | |
} | |
void * Class4Ctor(void *self) | |
{ | |
if(!self) return NULL; | |
Class_t *_class = (Class_t *)self; | |
printf("\n%s\n", __func__); | |
ClassInfo(self); | |
return self; | |
} | |
void * Class5Ctor(void *self) | |
{ | |
if(!self) return NULL; | |
Class_t *_class = (Class_t *)self; | |
printf("\n%s\n", __func__); | |
ClassInfo(self); | |
return self; | |
} | |
void * ClassCreate(void *self) | |
{ | |
if(!self) return NULL; | |
printf("%s\n", __func__); | |
Class_t *_class1 = (Class_t *)self; | |
void *constructed_class = NULL; | |
size_t totalSize = 0; | |
for(Class_t *_class = _class1; _class != &ObjectBase; _class = _class->_super) | |
{ | |
class_ctor_t ctor = _class->ctor; | |
if(ctor) | |
{ | |
printf("Constructing class=%p\n", _class); | |
constructed_class = ctor(_class); | |
totalSize += _class->impl.size; | |
} | |
if(_class->_super) | |
{ | |
_class->_super->_sub = _class; | |
} | |
} | |
printf("Created object with size of %zu bytes\n", totalSize); | |
return constructed_class; | |
} | |
void ClassInfo(void *self) | |
{ | |
printf("\n%s\n\n", __func__); | |
if(!self) | |
{ | |
printf("Could not find info for class.\n"); | |
return; | |
} | |
Class_t *_class = (Class_t *)self; | |
printf("Class_ID=%d\nClass_Size=%d\nClass_Name=%s\n", _class->impl.id, _class->impl.size, _class->impl.name); | |
printf("Super=%p, Sub=%p\n", _class->_super, _class->_sub); | |
} | |
Class_t *CastClass(void *self, Class_t *to_class) | |
{ | |
if(!(self && to_class)) return NULL; | |
if(to_class == &ObjectBase) to_class = *((Class_t **)to_class); | |
Class_t *_upcast = self, *_downcast = self; | |
while((_upcast || _downcast)) | |
{ | |
if(_upcast) | |
{ | |
if(_upcast->impl.id == to_class->impl.id) return _upcast; | |
_upcast = _upcast->_super; | |
} | |
if(_downcast) | |
{ | |
if(_downcast->impl.id == to_class->impl.id) return _downcast; | |
_downcast = _downcast->_sub; | |
} | |
} | |
return NULL; | |
} | |
void Class1Function(void *self) | |
{ | |
if(!self) return; | |
printf("\n%s\n\n", __func__); | |
Class_t *_class = CastClass(self, &Class1); | |
if(!_class) printf("Cannot execute %s for %p\n", __func__, self); | |
ClassInfo(_class); | |
} | |
void ObjectNotify(Object_t *self, Event_t event) | |
{ | |
if(!self) return; | |
self->HandleEvent(self, event); | |
} | |
void Class2Function(void *self) | |
{ | |
if(!self) return; | |
printf("\n%s\n\n", __func__); | |
Object_t *_obj = CastClass(self, &Class2); | |
if(!_obj) printf("Cannot execute %s for %p\n", __func__, self); | |
ClassInfo(_obj); | |
Event_t event = { | |
.type = NOTIFY_EVENT, | |
.desc = "Notify" | |
}; | |
printf("_obj=%p, ObjectBase=%p\n", _obj, &ObjectBase); | |
_obj = CastClass(_obj, &ObjectBase); | |
printf("_obj=%p, ObjectBase=%p\n", _obj, &ObjectBase); | |
printf("offsetof class=%zu\n", offsetof(__typeof__(*_obj), _base)); | |
if(!_obj) printf("null object\n"); | |
if(!_obj->_vptr) printf("null object vptr\n"); | |
if(!_obj->_vptr->notify) printf("null object vptr notify\n"); | |
_obj->_vptr->notify(_obj, event); | |
} | |
Class_t Class_Animal = { | |
._super = NULL, | |
._sub = NULL, | |
.impl = { | |
.size = 8, | |
.id = 1, | |
.name = "Animal" | |
}, | |
.ctor = NULL | |
}; | |
typedef struct | |
{ | |
Class_t *_class; | |
} Animal_t; | |
Animal_t Animal = { | |
._class = &Class_Animal | |
}; | |
void DisplayAnimal(void *self) | |
{ | |
if(!self) return; | |
printf("%s\n", __func__); | |
printf("Class_Animal=%p, Animal=%p\n", &Class_Animal, *((Class_t **)self)); | |
} | |
int main(void) { | |
printf("Class_Animal=%p, Animal=%p\n", &Class_Animal, &Animal); | |
DisplayAnimal(&Animal); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment