上一篇介绍了lw_oopc v1.2当中的一些宏定义,以及如何使用这些宏定义,总体来说使用起来还是非常简单的。这一篇既然叫做my_oopc,那么就来说一说优化和增加了一些功能之后的lw_oopc会是什么样子。沿用上一篇的流程,先用表格列举一下my_oopc相对于lw_oopc来说的不同之处:
my_oopc新增 | 类型 | 创作目的(为了解决什么问题?) |
---|---|---|
oopc_base_t | 结构体 | 记录当前类的部分信息以及当前类的父类和子类中此结构的地址 |
CLASS_NEW | 宏 | 用于方便的创建一个类的对象 |
CLASS_DELETE | 宏 | 用于方便的销毁一个类的对象 |
OVERRIDE_FUNC_SETTING | 宏 | 用于给父类中被子类继承的函数指针赋值 |
IMPLEMENT_FUNC_SETTING | 宏 | 用于给当前类实现的接口中的函数指针赋值 |
lw_oopc中的CLASS宏比较简单,基本上就是声明了创建/销毁对象,构造/析构对象等函数以及typedef一个结构体。 这样是比较简洁,且不会有性能和空间上的浪费。但这也就表明了,其功能的单一和薄弱。
比如lw_oopc当中的CLASS虽然有继承的实现,但在销毁对象的时候必须使用子类的delete函数,并不能如c++般,即便是拿到基类的对象指针,也能对对象进行销毁动作。所以在my_oopc当中会牺牲一点点的
空间来存放子类和基类的相关信息,并牺牲一点点性能来更好的销毁对象。
废话就不多说了,咱先来看看my_oopc中CLASS宏的定义:
#define CLASS(type) \
typedef struct type type; \
type* type##_new(OOPC_CTOR_PARAM); \
void type##_ctor(type* t); \
int type##_dtor(void* t); \
struct type{
#define END_CLASS oopc_base_t __obj;};
从这组宏定义可以看出,与lw_oopc基本相同,只是在结构体的末尾多了一个__obj这样的结构体变量,
其声明如下:
typedef int(*class_dtor_f)(void* classhd);
typedef struct oopc_base_s
{
unsigned int isDeleted;/* 记录当前类的对象是否已经被释放了 */
const char* name;/*记录类的名字*/
void* cthis; /*记录对象的地址*/
class_dtor_f dtor; /*析构函数*/
struct oopc_base_s* parent; /*记录父类对象的oopc_base_t结构的地址(无父类此为NULL)*/
struct oopc_base_s* child; /*记录子类对象的oopc_base_t结构的地址(无子类此为NULL)*/
}oopc_base_t;
它其实是一个双链表会记录当前类的对象的一些信息,并记录当前类的子类对象以及父类对象的信息结构体的地址。在32位的系统上,其消耗的内存为 24 字节。 从这个结构体中还可以看出一个细节, 那就是这里是使用回调函数(class_dtor_f dtor)来实现对象的析构,这样就可以不需 要依赖类名匹配来调用析构函数了。ABS_CLASS的定义和CLASS一样都将会包含oopc_base_t结构体, 而INTERFACE的定义和lw_oopc中的一样(因为其不会构建/析构)。
#define CTOR(type) \
type* type##_new(OOPC_CTOR_PARAM) { \
struct type *cthis; \
cthis = (struct type*)OOPC_MALLOC(sizeof(struct type), #type, file, line); \
if (!cthis){ \
return 0; \
} \
memset(cthis, 0, sizeof(*cthis)); \
cthis->__obj.name = #type; \
cthis->__obj.isDeleted = OOPC_FALSE; \
type##_ctor(cthis); \
return cthis; \
} \
\
void type##_ctor(type* cthis) {cthis->__obj.cthis = cthis;
#define END_CTOR }
从上面的宏可以看出,其并没有对oopc_base_t结构体中的parent和child指针进行赋值,因为默认情况下,此两个值都应该是NULL,即一个类即没有父类,也没有子类。对这两个指针进行赋值的动作是在SUPER_CTOR宏中进行的,表明当前类有父类,也同时表明当前类的父类有子类(有点儿绕),其宏定义如下:
#define SUPER_CTOR(father) \
father##_ctor(SUPER_PTR(cthis, father)); \
(cthis->##father).__obj.child = &(cthis->__obj); \
cthis->__obj.parent = &((cthis->##father).__obj)
在上一篇中,lw_oopc创建一个类的对象,都是直接调用声明类的时候声明的创建对象的函数,也就是说创建不同的类的对象的时候需要调用不同的函数。如:
Fish* fish = Fish_new(); // 创建鱼对象
Dog* dog = Dog_new(); // 创建狗对象
这样其实并不太方便,感觉上也会比较混乱一点。然后就是关于销毁对象的接口,在上一篇中因为比较简单,类的内部并未进行内存分配,故而并未使用类的析构函数,而是直接调用的一个释放内存的函数来进行对象的销毁。这样也是不够灵活和安全的。所以笔者在my_oopc中就新增了两个了宏CLASS_NEW/CLASS_DELETE来分别实现类的对象的创建和销毁。其具体的宏定义如下:
#define CLASS_NEW(type) \
type##_new(__FILE__, __LINE__)
对于CLASS_NEW宏的实现是非常简单的,就是通过传入类的名字来匹配创建对象的函数。当然这里并不是最优的做法,因为这里也是调用了每个类都会定义一个的创建对象的函数,但事实上这些函数所做的事情就本上都是一样的(只是类的名字不一样),然而以目前的这种实现方式,每定义一个类就需要实现一个创建对象的函数,这些代码都是冗余的。后续笔者将会说明这些进一步的优化(就好比my_oopc ver 0.2)。
#define CLASS_DELETE(classPtr) \
do{const char* name = NULL; \
oopc_base_t* obj = &((classPtr)->__obj); \
while (obj->child != NULL) obj = obj->child; /*find last child,because last child need destruct first */ \
name = obj->name; \
do{if ((obj->isDeleted == OOPC_FALSE) && obj->dtor){if (obj->dtor(obj->cthis) != OOPC_TRUE)break;} \
obj->isDeleted = OOPC_TRUE; \
if (!obj->parent){ OOPC_DELETE(classPtr, name); /*free instance memory*/ break; } \
obj = obj->parent; \
} while (obj != NULL);/*destruct from last child to last parent */ \
} while (0)
因为对象销毁的顺序是先子类,后基类,所以这里就需要通过一个循环,找到最末端的子类,然后依次先子类后父类的运行对象的析构函数,当所有析构函数都运行结束之后才会真正的释放对象的内存。
my_oopc中在lw_oopc的FUNCTION_SETTING宏基础上新增了两个宏,用于对INTERFACE和ABS_CLASS中定义的方法指针进行赋值,其定义如下:
#define OVERRIDE_FUNC_SETTING(father, f1, f2) cthis->##father##.f1 = f2
#define IMPLEMENT_FUNC_SETTING OVERRIDE_FUNC_SETTING
#ifndef __MY_OOPC_H__
#define __MY_OOPC_H__
#ifdef __cplusplus
extern "C"{
#endif
/*************************************************************************** * * macro define * ***************************************************************************/
#if defined(HAVE_STD_OFFSETOF)
#define USE_STD_OFFSETOF
#else
#define USE_USER_DEF_OFFSETOF
#endif
//////////////////////////////////////////////////////////////////////////
#define OOPC_MALLOC(size, typeName, fileName, lineNum) malloc(size)
#define OOPC_FREE free
#define OOPC_DELETE(cthis, name) printf("delete obj(%s), class(%s)\n",#cthis, ##name); OOPC_FREE(cthis)
#define OOPC_CTOR_PARAM const char* file, int line
#define OOPC_TRUE 1
#define OOPC_FALSE 0
//////////////////////////////////////////////////////////////////////////
#if defined(USE_STD_OFFSETOF)
#include <stddef.h>
#define OOPC_OFFSETOF offsetof
#elif defined(USE_USER_DEF_OFFSETOF)
#define OOPC_OFFSETOF(s,m) (size_t)&(((s*)0)->m)
#endif
/*************************************************************************** * * data struct declaration * ***************************************************************************/
typedef int(*class_dtor_f)(void* classhd);
typedef struct oopc_base_s
{
unsigned int isDeleted;
const char* name;
void* cthis;
class_dtor_f dtor;
struct oopc_base_s* parent;
struct oopc_base_s* child;
}oopc_base_t;
/*************************************************************************** * * API declaration * ***************************************************************************/
//////////////////////////////////////////////////////////////////////////
/** * interface declaration,this just define function,cann't define data member */
#define INTERFACE(type) \
typedef struct type type; \
void type##_ctor(type* t); \
int type##_dtor(void* t); \
struct type{
#define END_INTERFACE };
/** * abstract class macro declaration */
#define ABS_CLASS(type) \
typedef struct type type; \
void type##_ctor(type* t); \
int type##_dtor(void* t); \
struct type{
#define END_ABS_CLASS oopc_base_t __obj;};
/** * class macro declaration */
#define CLASS(type) \
typedef struct type type; \
type* type##_new(OOPC_CTOR_PARAM); \
void type##_ctor(type* t); \
int type##_dtor(void* t); \
struct type{
#define END_CLASS oopc_base_t __obj;};
//////////////////////////////////////////////////////////////////////////
/*data/interface type: private, public */
#define PROTECTED_DATA(classType) struct classType##ProtectData{
#define END_PROTECTED_DATA }protectData;
//////////////////////////////////////////////////////////////////////////
/** constructor function define*/
#define CTOR(type) \
type* type##_new(OOPC_CTOR_PARAM) { \
struct type *cthis; \
cthis = (struct type*)OOPC_MALLOC(sizeof(struct type), #type, file, line); \
if (!cthis){ \
return 0; \
} \
memset(cthis, 0, sizeof(*cthis)); \
cthis->__obj.name = #type; \
cthis->__obj.isDeleted = OOPC_FALSE; \
type##_ctor(cthis); \
return cthis; \
} \
\
void type##_ctor(type* cthis) {cthis->__obj.cthis = cthis;
#define END_CTOR }
/** *destructor function define *note: if define destructor, then must call DTOR_FUNC_SETTING to set destructor function *see also DTOR_FUNC_SETTING */
#define DTOR(type) \
int type##_dtor(void* t){type* cthis = (type*)t;
#define END_DTOR return OOPC_TRUE;}
/** abstract class constructor function define */
#define ABS_CTOR(type) \
void type##_ctor(type* cthis) {cthis->__obj.cthis = cthis;
#define END_ABS_CTOR }
#define ABS_DTOR DTOR
#define END_ABS_DTOR END_DTOR
//////////////////////////////////////////////////////////////////////////
#define FUNCTION_SETTING(f1, f2) cthis->f1 = f2
#define OVERRIDE_FUNC_SETTING(father, f1, f2) cthis->##father##.f1 = f2
#define IMPLEMENT_FUNC_SETTING OVERRIDE_FUNC_SETTING
/** *if defined destructor, then must call this macro to set destructor function *see also DTOR */
#define DTOR_FUNC_SETTING(type) cthis->__obj.dtor = type##_dtor
#define ABS_DTOR_FUNC_SETTING DTOR_FUNC_SETTING
#define PROTECTED_FUNC_SETTING(f1, f2) OVERRIDE_FUNC_SETTING(protectData, f1, f2)
//////////////////////////////////////////////////////////////////////////
#define IMPLEMENTS(type) struct type type
#define EXTENDS(type) struct type type
//////////////////////////////////////////////////////////////////////////
#define SUPER_PTR(cthis, father) ((father*)(&(cthis->##father)))
#define SUPER_PTR_2(cthis, father, grandfather) \
SUPER_PTR(SUPER_PTR(cthis, father), grandfather)
#define SUPER_PTR_3(cthis, father, grandfather, greatgrandfather) \
SUPER_PTR(SUPER_PTR_2(cthis, father, grandfather), greatgrandfather)
/**!!!!!!!note PROTECTE just inner use or inherit class!!!!!!!!!!!!!*/
#ifdef __cplusplus /*c++ have scope limit */
#define PROTECTED_DATA_TYPE(classType) struct classType::classType##ProtectData
#else
#define PROTECTED_DATA_TYPE(classType) struct classType##ProtectData
#endif
#define PROTECTED_PTR(cthis, classType) ((PROTECTED_DATA_TYPE(classType)*)(&((cthis)->##protectData)))
#define SUPER_PROTECTED_PTR(cthis, father) PROTECTED_PTR(SUPER_PTR(cthis, father), father)
//////////////////////////////////////////////////////////////////////////
#define SUPER_CTOR(father) \
father##_ctor(SUPER_PTR(cthis, father)); \
(cthis->##father).__obj.child = &(cthis->__obj); \
cthis->__obj.parent = &((cthis->##father).__obj)
//////////////////////////////////////////////////////////////////////////
#define SUB_PTR(selfptr, self, child) \
((child*)((char*)selfptr - OOPC_OFFSETOF(child, self)))
#define SUB_PTR_2(selfptr, self, child, grandchild) \
SUB_PTR(SUB_PTR(selfptr, self, child), child, grandchild)
#define SUB_PTR_3(selfptr, self, child, grandchild, greatgrandchild) \
SUB_PTR(SUB_PTR_2(selfptr, self, child, grandchild), grandchild, greatgrandchild)
#define INHERIT_FROM(father, cthis, field) cthis->father.field
//////////////////////////////////////////////////////////////////////////
/** create a class instance */
#define CLASS_NEW(type) \
type##_new(__FILE__, __LINE__)
/** release a class instance */
#define CLASS_DELETE(classPtr) \
do{const char* name = NULL; \
oopc_base_t* obj = &((classPtr)->__obj); \
while (obj->child != NULL) obj = obj->child; /*find last child,because last child need destruct first */ \
name = obj->name; \
do{if ((obj->isDeleted == OOPC_FALSE) && obj->dtor){if (obj->dtor(obj->cthis) != OOPC_TRUE)break;} \
obj->isDeleted = OOPC_TRUE; \
if (!obj->parent){ OOPC_DELETE(classPtr, name); /*free instance memory*/ break; } \
obj = obj->parent; \
} while (obj != NULL);/*destruct from last child to last parent */ \
} while (0)
#ifdef __cplusplus
}
#endif
#endif //end of __MY_OOPC_H__
还是以各种动物为例子:
/* 接口,基类,子类的声明 */
INTERFACE(IMoveable)
void(*move)(IMoveable* t); // Move行为
END_INTERFACE
ABS_CLASS(Animal)
char name[128]; // 动物的昵称(假设小于128个字符)
int age; // 动物的年龄
void(*setName)(Animal* t, const char* name); // 设置动物的昵称
void(*setAge)(Animal* t, int age); // 设置动物的年龄
void(*sayHello)(Animal* t); // 动物打招呼
void(*eat)(Animal* t); // 动物都会吃(抽象方法,由子类实现)
void(*breathe)(Animal* t); // 动物都会呼吸(抽象方法,由子类实现)
void(*init)(Animal* t, const char* name, int age); // 初始化昵称和年龄
END_ABS_CLASS
CLASS(Fish)
EXTENDS(Animal); // 继承Animal抽象类
IMPLEMENTS(IMoveable); // 实现IMoveable接口
void(*init)(Fish* t, const char* name, int age);
END_CLASS
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/*具体定义*/
/* 设置动物的昵称 */
void Animal_setName(Animal* t, const char* name)
{
// 这里假定name小于128个字符,为简化示例代码,不做保护(产品代码中不要这样写)
strcpy(t->name, name);
}
/* 设置动物的年龄 */
void Animal_setAge(Animal* t, int age)
{
t->age = age;
}
/* 动物和我们打招呼 */
void Animal_sayHello(Animal* t)
{
LOGD("Hello! 我是%s,今年%d岁了!\n", t->name, t->age);
}
/* 初始化动物的昵称和年龄 */
void Animal_init(Animal* t, const char* name, int age)
{
t->setName(t, name);
t->setAge(t, age);
}
ABS_CTOR(Animal)/*animal 类的构造函数*/
ABS_DTOR_FUNC_SETTING(Animal);
FUNCTION_SETTING(setName, Animal_setName);
FUNCTION_SETTING(setAge, Animal_setAge);
FUNCTION_SETTING(sayHello, Animal_sayHello);
FUNCTION_SETTING(init, Animal_init);
END_ABS_CTOR
ABS_DTOR(Animal)/*animal 类的析构函数*/
LOGD("Animal base class dtor\n");
END_ABS_DTOR
/* 鱼的吃行为 */
void Fish_eat(Animal* t)
{
LOGD("鱼吃水草!\n");
}
/* 鱼的呼吸行为 */
void Fish_breathe(Animal* t)
{
LOGD("鱼用鳃呼吸!\n");
}
/* 鱼的移动行为 */
void Fish_move(IMoveable* t)
{
LOGD("鱼在水里游!\n");
}
/* 初始化鱼的昵称和年龄 */
void Fish_init(Fish* t, const char* name, int age)
{
Animal* animal = SUPER_PTR(t, Animal);
animal->setName(animal, name);
animal->setAge(animal, age);
}
CTOR(Fish) /*fish 类的构造函数 */
SUPER_CTOR(Animal);
DTOR_FUNC_SETTING(Fish);
OVERRIDE_FUNC_SETTING(Animal, eat, Fish_eat);
OVERRIDE_FUNC_SETTING(Animal, breathe, Fish_breathe);
IMPLEMENT_FUNC_SETTING(IMoveable, move, Fish_move);
FUNCTION_SETTING(init, Fish_init);
END_CTOR
DTOR(Fish)/*fish 类的析构函数*/
LOGD("fish class dtor\n");
END_DTOR
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/*应用实例*/
int main(int argc, char* argv[])
{
Animal* animal = NULL;
IMoveable* moveObj = NULL;
Fish* fish = CLASS_NEW(Fish); // 创建鱼对象
fish->init(fish, "小鲤鱼", 1); // 初始化鱼对象的昵称为:小鲤鱼,年龄为:1岁
animal = SUPER_PTR(fish, Animal); // 将fish指针转型为Animal类型指针
//打印动物容器内的动物信息
animal->eat(animal);
animal->breathe(animal);
animal->sayHello(animal);
//打印可移动物体容器内的可移动物体移动方式的信息
moveObj->move(moveObj);
CLASS_DELETE(fish); /*使用当前类的对象指针销毁fish对象*/
fish = CLASS_NEW(Fish); // 创建鱼对象
fish->init(fish, "小鲤鱼", 1); // 初始化鱼对象的昵称为:小鲤鱼,年龄为:1岁
animal = SUPER_PTR(fish, Animal); // 将fish指针转型为Animal类型指针
CLASS_DELETE(animal); /*使用当前类的父类的对象指针销毁fish对象*/
return 0;
}
如第3节中所说的,对于类的对象创建函数部分还可以再次优化,以节省编译后的二进制size。同理,销毁对象的宏(CLASS_DELETE)也可以进行一些优化。
#define CLASS(type) \
typedef struct type type; \
void type##_ctor(void* t); \
int type##_dtor(void* t); \
struct type{
#define END_CLASS oopc_base_t __obj;};
/** constructor function define*/
#define CTOR(type) \
void type##_ctor(void* t) {type* cthis = (type*)t; cthis->__obj.cthis = cthis;
#define CLASS_NEW(type) \
(type*)oopcCreate(__FILE__, __LINE__, #type, sizeof(type), type##_ctor)
#define CLASS_DELETE(classPtr) \
oopcDestory(__FILE__, __LINE__, classPtr, sizeof(*(classPtr)))
在这里创建对象和销毁对象都是通过函数去完成的,这两个的定义如下:
void* oopcCreate(const char* file, int line, const char* className, unsigned int size, void(*ctor)(void* t))
{
void* cthis = OOPC_MALLOC(size, className, file, line);
if (!cthis)
{
return 0;
}
memset(cthis, 0, size);
oopc_base_t* _obj = (oopc_base_t*)((char*)cthis + size - sizeof(oopc_base_t));
_obj->name = className; /*todo,使用数组或分配内存保存类名*/
_obj->isDeleted = OOPC_FALSE;
ctor(cthis);
return cthis;
}
void oopcDestory(const char* file, int line, void* classPtr, unsigned int size)
{
const char* name = NULL;
oopc_base_t* obj = (oopc_base_t*)((char*)classPtr + size - sizeof(oopc_base_t));
while (obj->child != NULL)
{
obj = obj->child; /*find last child,because last child need destruct first */
}
name = obj->name;
do
{
if ((obj->isDeleted == OOPC_FALSE) && obj->dtor)
{
if (obj->dtor(obj->cthis) != OOPC_TRUE)
{
break;
}
}
obj->isDeleted = OOPC_TRUE;
if (!obj->parent)
{
OOPC_DELETE(classPtr, name); /*free instance memory*/
break;
}
obj = obj->parent;
} while (obj != NULL);/*destruct from last child to last parent */ \
}
这样虽然然后类的对象的创建和销毁都是使用统一的函数,走统一的流程,但为了不让编译之后的二进制膨胀,就只能将上面这个两个函数放在 .c文件中,也就是这套my_oopc除了my_oopc.h这样一个头文 件之外还需要增加一个my_oopc.c文件用于存放函数定义。虽然这增加了一个文件,但是有效的减少了用户代码编译后的二进制膨胀,且在函数里面实现这些流程也增加了类型安全和可调试性。
具体应用的例子和第5节中的例子是一样的,就不在多讲了,现在就来看看my_oopc(ver0.2)的完整实现:
#ifndef __MY_OOPC_H__
#define __MY_OOPC_H__
#ifdef __cplusplus
extern "C"{
#endif
/*************************************************************************** * * macro define * ***************************************************************************/
#if defined(HAVE_STD_OFFSETOF)
#define USE_STD_OFFSETOF
#else
#define USE_USER_DEF_OFFSETOF
#endif
//////////////////////////////////////////////////////////////////////////
#define OOPC_MALLOC(size, typeName, fileName, lineNum) malloc(size)
#define OOPC_FREE free
#define OOPC_DELETE(cthis, name) printf("delete obj(%s), class(%s)\n",#cthis, ##name); OOPC_FREE(cthis)
#define OOPC_CTOR_PARAM const char* file, int line
#define OOPC_TRUE 1
#define OOPC_FALSE 0
//////////////////////////////////////////////////////////////////////////
#if defined(USE_STD_OFFSETOF)
#include <stddef.h>
#define OOPC_OFFSETOF offsetof
#elif defined(USE_USER_DEF_OFFSETOF)
#define OOPC_OFFSETOF(s,m) (size_t)&(((s*)0)->m)
#endif
/*************************************************************************** * * data struct declaration * ***************************************************************************/
typedef int(*class_dtor_f)(void* classhd);
typedef struct oopc_base_s
{
unsigned int isDeleted;
const char* name;
void* cthis;
class_dtor_f dtor;
struct oopc_base_s* parent;
struct oopc_base_s* child;
}oopc_base_t;
/*************************************************************************** * * API declaration * ***************************************************************************/
//////////////////////////////////////////////////////////////////////////
/** * interface declaration,this just define function,cann't define data member */
#define INTERFACE(type) \
typedef struct type type; \
void type##_ctor(type* t); \
int type##_dtor(void* t); \
struct type{
#define END_INTERFACE };
/** * abstract class declaration,this class */
#define ABS_CLASS(type) \
typedef struct type type; \
void type##_ctor(type* t); \
int type##_dtor(void* t); \
struct type{
#define END_ABS_CLASS oopc_base_t __obj;};
/** * class declaration,this class */
#define CLASS(type) \
typedef struct type type; \
void type##_ctor(void* t); \
int type##_dtor(void* t); \
struct type{
#define END_CLASS oopc_base_t __obj;};
//////////////////////////////////////////////////////////////////////////
/*data/interface type: private, public */
#define PROTECTED_DATA(classType) struct classType##ProtectData{
#define END_PROTECTED_DATA }protectData;
//////////////////////////////////////////////////////////////////////////
/** constructor function define*/
#define CTOR(type) \
void type##_ctor(void* t) {type* cthis = (type*)t; cthis->__obj.cthis = cthis;
#define END_CTOR }
/** *destructor function define *note: if define destructor, then must call DTOR_FUNC_SETTING to set destructor function *see also DTOR_FUNC_SETTING */
#define DTOR(type) \
int type##_dtor(void* t){type* cthis = (type*)t;
#define END_DTOR return OOPC_TRUE;}
/** abstract class constructor function define */
#define ABS_CTOR(type) \
void type##_ctor(type* cthis) {cthis->__obj.cthis = cthis;
#define END_ABS_CTOR }
#define ABS_DTOR DTOR
#define END_ABS_DTOR END_DTOR
//////////////////////////////////////////////////////////////////////////
#define FUNCTION_SETTING(f1, f2) cthis->f1 = f2
#define OVERRIDE_FUNC_SETTING(father, f1, f2) cthis->##father##.f1 = f2
#define IMPLEMENT_FUNC_SETTING OVERRIDE_FUNC_SETTING
/** *if defined destructor, then must call this macro to set destructor function *see also DTOR */
#define DTOR_FUNC_SETTING(type) cthis->__obj.dtor = type##_dtor
#define ABS_DTOR_FUNC_SETTING DTOR_FUNC_SETTING
#define PROTECTED_FUNC_SETTING(f1, f2) OVERRIDE_FUNC_SETTING(protectData, f1, f2)
//////////////////////////////////////////////////////////////////////////
#define IMPLEMENTS(type) struct type type
#define EXTENDS(type) struct type type
//////////////////////////////////////////////////////////////////////////
#define SUPER_PTR(cthis, father) ((father*)(&(cthis->##father)))
#define SUPER_PTR_2(cthis, father, grandfather) \
SUPER_PTR(SUPER_PTR(cthis, father), grandfather)
#define SUPER_PTR_3(cthis, father, grandfather, greatgrandfather) \
SUPER_PTR(SUPER_PTR_2(cthis, father, grandfather), greatgrandfather)
/**!!!!!!!note PROTECTE just inner use or inherit class!!!!!!!!!!!!!*/
#ifdef __cplusplus /*c++ have scope limit */
#define PROTECTED_DATA_TYPE(classType) struct classType::classType##ProtectData
#else
#define PROTECTED_DATA_TYPE(classType) struct classType##ProtectData
#endif
#define PROTECTED_PTR(cthis, classType) ((PROTECTED_DATA_TYPE(classType)*)(&((cthis)->##protectData)))
#define SUPER_PROTECTED_PTR(cthis, father) PROTECTED_PTR(SUPER_PTR(cthis, father), father)
//////////////////////////////////////////////////////////////////////////
#define SUPER_CTOR(father) \
father##_ctor(SUPER_PTR(cthis, father)); \
(cthis->##father).__obj.child = &(cthis->__obj); \
cthis->__obj.parent = &((cthis->##father).__obj)
//////////////////////////////////////////////////////////////////////////
#define SUB_PTR(selfptr, self, child) \
((child*)((char*)selfptr - OOPC_OFFSETOF(child, self)))
#define SUB_PTR_2(selfptr, self, child, grandchild) \
SUB_PTR(SUB_PTR(selfptr, self, child), child, grandchild)
#define SUB_PTR_3(selfptr, self, child, grandchild, greatgrandchild) \
SUB_PTR(SUB_PTR_2(selfptr, self, child, grandchild), grandchild, greatgrandchild)
#define INHERIT_FROM(father, cthis, field) cthis->father.field
//////////////////////////////////////////////////////////////////////////
/** create a class instance */
#define CLASS_NEW(type) \
(type*)oopcCreate(__FILE__, __LINE__, #type, sizeof(type), type##_ctor)
/** release a class instance */
#define CLASS_DELETE(classPtr) \
oopcDestory(__FILE__, __LINE__, classPtr, sizeof(*(classPtr)))
void* oopcCreate(const char* file, int line, const char* className, unsigned int size, void(*ctor)(void* t));
void oopcDestory(const char* file, int line, void* classPtr, unsigned int size);
#ifdef __cplusplus
}
#endif
#endif //end of __MY_OOPC_H__
#include "my_oopc.h"
void* oopcCreate(const char* file, int line, const char* className, unsigned int size, void(*ctor)(void* t))
{
void* cthis = OOPC_MALLOC(size, className, file, line);
if (!cthis)
{
return 0;
}
memset(cthis, 0, size);
oopc_base_t* _obj = (oopc_base_t*)((char*)cthis + size - sizeof(oopc_base_t));
_obj->name = className; /*todo,使用数组或分配内存保存类名*/
_obj->isDeleted = OOPC_FALSE;
ctor(cthis);
return cthis;
}
void oopcDestory(const char* file, int line, void* classPtr, unsigned int size)
{
const char* name = NULL;
oopc_base_t* obj = (oopc_base_t*)((char*)classPtr + size - sizeof(oopc_base_t));
while (obj->child != NULL)
{
obj = obj->child; /*find last child,because last child need destruct first */
}
name = obj->name;
do
{
if ((obj->isDeleted == OOPC_FALSE) && obj->dtor)
{
if (obj->dtor(obj->cthis) != OOPC_TRUE)
{
break;
}
}
obj->isDeleted = OOPC_TRUE;
if (!obj->parent)
{
OOPC_DELETE(classPtr, name); /*free instance memory*/
break;
}
obj = obj->parent;
} while (obj != NULL);/*destruct from last child to last parent */ \
}
my_oopc是为了更方便的使用和调试在lw_oopc基础上优化,更改,增加了部分东西,当然这远远没有到极致,应该还可以做更多的优化。但这毕竟只是使用c语言去模拟面向对象和面向接口编程,如果花太多时间和精力去让这些宏,函数等更加完善,就有些得不偿失了,而且这也会增加其复杂度,再使用上可能不见得就会好上多少,一不小心可能就掉进了过度设计的陷阱。
至此关于c语言模拟面向对象/接口编程和lw_oopc宏以及基于lw_oopc宏优化的my_oopc等等东西的部分就结束了。后续再看看c语言中还有啥好玩儿的东东可以拿出来唠唠。