Skip to content

Instantly share code, notes, and snippets.

@tjhv
Created February 17, 2018 05:08
Show Gist options
  • Save tjhv/7a54aed6b90145485d004e0c5dc3e4a7 to your computer and use it in GitHub Desktop.
Save tjhv/7a54aed6b90145485d004e0c5dc3e4a7 to your computer and use it in GitHub Desktop.
Mock inheritance in C
#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