Mojoc strictly follow this OOC (Object Oriented C) programing model. The model is customized by C unique features, so it supports C language to build large and complex projects, and still remains simple to use and easy to understand.
The Singleton pattern is very important to Mojoc. In C language the data and behavior are separated and there is no namespace. The singleton can abstract a group of behavior and give it namespace. This model build a parallel data struct and behavior struct that correspond to the class of OOP model.
struct ADrawable
{
Drawable* (*Create)();
void (*Init) (Drawable* outDrawable);
};
extern struct ADrawable ADrawable[1];
- The
ADrawable
is singleton, global unique. - The struct
ADrawable
is type name,ADrawable[1]
is object name. - The
ADrawable
object defined as an array, can let it use like a ptr.
static Drawable* Create()
{
return (Drawable*) malloc(sizeof(Drawable));
}
static void Init(Drawable* outDrawable)
{
// init outDrawable
}
struct ADrawable ADrawable[1] =
{
Create,
Init,
};
- Just initialize the singleton
ADrawable
object.
typedef struct Drawable Drawable;
struct Drawable
{
float positionX;
float positionY;
};
typedef struct
{
Drawable* (*Create)();
void (*Init) (Drawable* outDrawable);
}
ADrawable;
extern ADrawable ADrawable[1];
- The
Drawable
object hold the data. - The
ADrawable
object hold the behavior. - The
Create
function malloc theDrawable
memory like new keyword. - The Init function initialize
Drawable
which memory already exists, often in stack or in superclass memory.
The inheritance is superclass struct all datas are embedded in subclass struct. Then one malloc can get all memory in inheritance chain, and one free on subclass object can release all memory in inheritance chain.
typedef struct Drawable Drawable;
struct Drawable
{
int a;
};
typedef struct
{
Drawable drawable[1];
}
Sprite;
struct ASprite
{
Sprite* (*Create)();
void (*Init) (Sprite* outSprite);
};
- The
Drawable
is superclass. - The
Sprite
is subclass. - The
drawable[1]
as an array, can let it use like a ptr. - In
ASprite
functionCreate
andInit
, indirect callADrawable->Init
for initialize superclass memory. - In C there is no limit of inheritance number, the subclass can inheritance any numbers of superclass — this is a new angle of abstract.
/**
* Get struct pointer from member pointer.
* this for memberPtr same as memberName.
*
* memberPtr: the pointer that point struct's member.
* it's the member address offset from struct address.
*
*/
#define AStruct_GetParent(memberPtr, ParentType) \
((ParentType*) ((char*) (memberPtr) - offsetof(ParentType, memberPtr)))
Sprite* sprite = AStruct_GetParent(drawable, Sprite);
- First, get the superclass offset in subclass struct.
- Second, get the subclass ptr from superclass ptr by superclass offset.
- With this ability, we can hold superclass ptr execute same interface, but different implementation of subclass — this is polymorphism.
The composite is independent struct ptr are embedded in struct .
typedef struct Drawable Drawable;
struct Drawable
{
Drawable* parent;
};
- The parent composite into
Drawable
, the memory manage by independentCreate
andRelease
of parent.
typedef struct Drawable Drawable;
struct Drawable
{
void (*Draw)(Drawable* drawable);
};
The function Draw
in struct, means different Drawable
object can has own implementation of Draw
.
typedef struct
{
Drawable drawable[1];
}
Hero;
typedef struct
{
Drawable drawable[1];
}
Enemy;
Drawable drawables[] =
{
hero->drawable,
enemy->drawable,
};
for (int i = 0; i < 2; ++i)
{
Drawable* drawable = drawables[i];
drawable->Draw(drawable);
}
The Hero
and Enemy
implement own Draw
behavior.
In inheritance chain, usually need to override superclass function and call superclass function.
typedef struct
{
Drawable drawable[1];
}
Sprite;
struct ASprite
{
void (*Draw)(Drawable* drawable);
};
extern ASprite ASprite;
If we want to override Sprite's Draw
function:
- First, need to publish
Draw
toASprite
; - Second, override
Draw
function; - Then, we can still call the original
Draw
byASprite
.
typedef struct
{
Sprite sprite[1];
}
SpriteBatch;
// subclass implementation
static void SpriteBatchDraw(Drawable* drawable)
{
// call father
ASprite->Draw(drawable);
// do extra things...
}
// override
spriteBatch->sprite->drawable->Draw = SpriteBatchDraw;
Create
— malloc struct memory and delete byfree
andRelease
if needed.Init
— initialize struct memory and delete byRelease
if needed.Release
— delete struct member ptr memory which composite into struct andCreate
by struct self.Destroy
— firstRelease
thenfree
.
Mojoc uses OOC Spine to implement the Java OOP Spine.
🚀