都知道C语言是面向过程的,但是现在软件规模越来越大,通过面向对象的方式可以简化开发。业余时间想了个简单的方法,在C中使用一部分面向对象的基本功能。由于C语言自身的限制,并不完善,只能将就用,聊胜于无,如果大家有好的想法可以一起讨论。
首先还是老规矩上代码: https://files.cnblogs.com/GhostZCH/object.rar
面向对象有三个基本属性:封装、继承和多态。 此处一一讲解处理方法。
1. 封装,基本思想就是用结构体代替类,属性没什么好说的,方法就麻烦点只能用函数指针了,基本思想和JS差不多,“函数就是对象的一个属性”。 缺点试试无法控制访问的私有和公用。由于C没有this指针,只好在每个函数都增加一个void*的参数将自己传进去。
1 /************************************************************************/
2 /* object 基类 */
3 /************************************************************************/
4
5
6 typedef struct stObj OBJECT_STRU;
7
8 typedef char* (*ToString_PF)(void *pObj, char *pcStrBuf);
9 typedef unsigned int ClassID;
10
11 struct stObj
12 {
13 ClassID m_uiCID;
14 ToString_PF pfToString;
15 };
16
17 char* OBJ_ToString(void *pObj, char *pcStrBuf)
18 {
19 sprintf(pcStrBuf, "ClassName:%s;ClassID:%06u", "Object", ((OBJECT_STRU *)pObj)->m_uiCID);
20 return pcStrBuf;
21 }
22
23 OBJECT_STRU *new_Object()
24 {
25 OBJECT_STRU* pstObj = (OBJECT_STRU*)malloc(sizeof(OBJECT_STRU));
26
27 if ( NULL == pstObj )
28 {
29 return NULL;
30 }
31
32 pstObj->m_uiCID = CID_OBJ;
33 pstObj->pfToString = OBJ_ToString;
34
35 return pstObj;
2 /* object 基类 */
3 /************************************************************************/
4
5
6 typedef struct stObj OBJECT_STRU;
7
8 typedef char* (*ToString_PF)(void *pObj, char *pcStrBuf);
9 typedef unsigned int ClassID;
10
11 struct stObj
12 {
13 ClassID m_uiCID;
14 ToString_PF pfToString;
15 };
16
17 char* OBJ_ToString(void *pObj, char *pcStrBuf)
18 {
19 sprintf(pcStrBuf, "ClassName:%s;ClassID:%06u", "Object", ((OBJECT_STRU *)pObj)->m_uiCID);
20 return pcStrBuf;
21 }
22
23 OBJECT_STRU *new_Object()
24 {
25 OBJECT_STRU* pstObj = (OBJECT_STRU*)malloc(sizeof(OBJECT_STRU));
26
27 if ( NULL == pstObj )
28 {
29 return NULL;
30 }
31
32 pstObj->m_uiCID = CID_OBJ;
33 pstObj->pfToString = OBJ_ToString;
34
35 return pstObj;
36 }
2继承:继承的方法是用类似组合的方式,将父类结构体作为子类的第一个属性,注意,这里必须是第一个,这样后面的强制类型转换才会有效。通过强制转换转换成父类。
1 /************************************************************************/
2 /* animal 子类一 */
3 /************************************************************************/
4
5 typedef struct stAnimal
6 {
7 // 父类实体,必须放在第一个,强制转换才有效,利用这种方法产生继承的效果
8 OBJECT_STRU m_stBaseObj;
9
10 // 新增属性
11 char acName[NAME_LEN];
12
13 // 也可增加新增方法
14 // int (* pfGetAge)();
15 }ANIMAL_STRU;
16
17 // 覆盖父类方法
18 char* ANM_ToString(void *pObj, char *pcStrBuf)
19 {
20 sprintf(pcStrBuf, "Classname:%s; AnimalName:%s; ClassID:%06u",
21 "Animal",
22 ((ANIMAL_STRU *)pObj)->acName,
23 ((ANIMAL_STRU *)pObj)->m_stBaseObj.m_uiCID);
24 return pcStrBuf;
25 }
26
27 ANIMAL_STRU *new_Animal()
28 {
29 ANIMAL_STRU* pstObj = (ANIMAL_STRU*)malloc(sizeof(ANIMAL_STRU));
30
31 if ( NULL == pstObj )
32 {
33 return NULL;
34 }
35
36 pstObj->m_stBaseObj.m_uiCID = CID_ANM;
37 pstObj->m_stBaseObj.pfToString = ANM_ToString; // 覆盖父类方法,产生多态效果
38 pstObj->acName[0] = '
3 /************************************************************************/
4
5 typedef struct stAnimal
6 {
7 // 父类实体,必须放在第一个,强制转换才有效,利用这种方法产生继承的效果
8 OBJECT_STRU m_stBaseObj;
9
10 // 新增属性
11 char acName[NAME_LEN];
12
13 // 也可增加新增方法
14 // int (* pfGetAge)();
15 }ANIMAL_STRU;
16
17 // 覆盖父类方法
18 char* ANM_ToString(void *pObj, char *pcStrBuf)
19 {
20 sprintf(pcStrBuf, "Classname:%s; AnimalName:%s; ClassID:%06u",
21 "Animal",
22 ((ANIMAL_STRU *)pObj)->acName,
23 ((ANIMAL_STRU *)pObj)->m_stBaseObj.m_uiCID);
24 return pcStrBuf;
25 }
26
27 ANIMAL_STRU *new_Animal()
28 {
29 ANIMAL_STRU* pstObj = (ANIMAL_STRU*)malloc(sizeof(ANIMAL_STRU));
30
31 if ( NULL == pstObj )
32 {
33 return NULL;
34 }
35
36 pstObj->m_stBaseObj.m_uiCID = CID_ANM;
37 pstObj->m_stBaseObj.pfToString = ANM_ToString; // 覆盖父类方法,产生多态效果
38 pstObj->acName[0] = '