OOC.md
February 18, 2021 · View on GitHub
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.
Singleton
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.
In .h file
struct ADrawable
{
Drawable* (*Create)();
void (*Init) (Drawable* outDrawable);
};
extern struct ADrawable ADrawable[1];
- The
ADrawableis singleton, global unique. - The struct
ADrawableis type name,ADrawable[1]is object name. - The
ADrawableobject defined as an array, can let it use like a ptr.
In .c file
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
ADrawableobject.
Encapsulation
In .h file
typedef struct Drawable Drawable;
struct Drawable
{
float positionX;
float positionY;
};
typedef struct
{
Drawable* (*Create)();
void (*Init) (Drawable* outDrawable);
}
ADrawable;
extern ADrawable ADrawable[1];
- The
Drawableobject hold the data. - The
ADrawableobject hold the behavior. - The
Createfunction malloc theDrawablememory like new keyword. - The Init function initialize
Drawablewhich memory already exists, often in stack or in superclass memory.
Inheritance
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
Drawableis superclass. - The
Spriteis subclass. - The
drawable[1]as an array, can let it use like a ptr. - In
ASpritefunctionCreateandInit, indirect callADrawable->Initfor 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.
How to visit subclass from superclass ?
/**
* 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.
Composite
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 independentCreateandReleaseof parent.
Polymorphism
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.
Override
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
DrawtoASprite; - Second, override
Drawfunction; - Then, we can still call the original
DrawbyASprite.
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;
Memory
Create— malloc struct memory and delete byfreeandReleaseif needed.Init— initialize struct memory and delete byReleaseif needed.Release— delete struct member ptr memory which composite into struct andCreateby struct self.Destroy— firstReleasethenfree.
Examples
Sample
Mojoc uses OOC Spine to implement the Java OOP Spine.
:rocket: