当第一次看到vxworks的源码时,我才真正明白了怎么用C语言来实现面向对象的功能;以前虽然遇到过类似的文章,不过总是没有动力去了解实际的原理,这次闲来无事,拿到vxworks的源码,才看出一些端倪。
用c语言实现面向对象,其实是蛮难的,毕竟c语言是纯面向过程的语言,而面向过程和面向对象是两种完全不同的思想,虽不能说格格不入,但至少共同点甚少。不过,c语言天生具有的两大特性成就了其实现面向对象的功能,这就是结构体和指针。熟悉面向对象的朋友都应该知道类和结构体的异同,两者其实是很类似的,甚至可以 这样说,类就是在结构体的基础上衍生而来的,有了结构体后,实现面向对象就不是一句空话。大家都知道,类无非由两部分组成,属性和方法。属性就相当于结构体的域,而方法呢,在C语言中,可以用函数指针来实现,这样,类就构成了。
废话少说,看个示例:
typedef struct obj_class /* OBJ_CLASS */
{
OBJ_CORE objCore; /* object core of class object */
struct mem_part *objPartId; /* memory partition to allocate from */
unsigned objSize; /* 对象大小 */
unsigned objAllocCnt; /* 已经分配的对象数目 */
unsigned objFreeCnt; /* 已经释放的对象数目 */
unsigned objInitCnt; /* 已经初始化的对象数目 */
unsigned objTerminateCnt;/* 已经终结的对象数目 */
int coreOffset; /* offset from object start to objCore*/
FUNCPTR createRtn; /* object creation routine */
FUNCPTR initRtn; /* object initialization routine */
FUNCPTR destroyRtn; /* object destroy routine */
FUNCPTR showRtn; /* object show routine */
FUNCPTR instRtn; /* object inst routine */
} OBJ_CLASS;
上面这个结构体含有8个成员,5个函数指针,就相当于类的8个属性和5个方法;为了更加深入地了解obj_class,有必要说说各个成员的类型,首先来看看OBJ_CORE,这个类型也是一个结构体,它只包含一个类型为obj_class指针的域:
typedef struct obj_core /* OBJ_CORE */
{
struct obj_class *pObjClass; /* pointer to object's class */
} OBJ_CORE;
相信大多数人应该已经猜到了obj_core的作用,如果没猜到也没关系,看到了后面的初始化函数以后相信大家都明白其作用了。接下来是objPartId,它是一个指向mem_part对象的指针,由于mem_part结构体十分复杂,而且后面会专门分析,因此本文暂不分析,大家只要知道这是一个结构体就可以了。最后一个值得说明的类型是FUNCPTR,使用过vxworks编程的朋友对这个类型肯定不会陌生,不过照顾所有人,还是将其定义描述一下:
typedef int (*FUNCPTR) (); /* ptr to function returning int */
描述完了obj_core的定义,下面看看与这个结构体相关的几个函数,函数不是很多,主要是对象创建、对象销毁函数,就相当于C++中的构造函数、析构函数一样,虽然对象创建、销毁最终还是调用obj_core结构体中定义的函数指针来实现的,但从这里,也可以看出,毕竟C语言不是面向对象的语言,要完全实现面向对象的功能,还是十分复杂的,需要借助一些辅助类来完成。说了半天,到底这些函数是什么呢?四个函数:classLibInit、classCreate、classInit和classDestroy(暂时未实现),另外还有一些相关的工具类函数这里就不细述了。上述四个函数(其实是三个函数)的关系可以用下图来表示:
classLibInit函数相当于class类的总类,用于初始化一个工具类对象;而classCreate则是实际的创建具体的对象的函数,其完成的工作,主要是两部分:内存分配和成员初始化。内存分配由objAlloc函数来实现,而成员初始化,则由classinit函数来实现。classInit函数就是具体的成员初始化函数,其职责很简单,将提供的参数赋值给obj_class的各个成员就足够了。上面曾经说过obj_core的作用,这里具体描述一下,在描述之前,先看看下面的代码:
STATUS classInit
(
OBJ_CLASS *pObjClass, /* pointer to object class to initialize */
unsigned objectSize, /* size of object */
int coreOffset, /* offset from objCore to object start */
FUNCPTR createRtn, /* object creation routine */
FUNCPTR initRtn, /* object initialization routine */
FUNCPTR destroyRtn /* object destroy routine */
)
{
/* default memory partition is system partition */
略
/* initialize object methods */
略
/* initialize class as valid object */
objCoreInit (&pObjClass->objCore, classClassId);
return (OK);
}
void objCoreInit
(
OBJ_CORE *pObjCore, /* pointer to object core to initialize */
OBJ_CLASS *pObjClass /* pointer to object class */
)
{
pObjCore->pObjClass = pObjClass; /* validate object */
pObjClass->objInitCnt ++; /* keep track of object count */
}
看完上面的代码以后,相应大多数人都会犯迷糊,因为有一个变量还没有介绍,这就是全局变量classClassId:
/* locals */
LOCAL OBJ_CLASS classClass;
/* globals */
CLASS_ID classClassId = &classClass;
从上面的classInit函数可以看出,只要是通过classCreate创建的对象,其objCore值都指向同一个变量,为什么要这样实现呢?这样实现的目的是为了便于实现类的标识。熟悉面向对象的朋友都知道,判断两个对象是否是同一个类太简单了,可以直接用==,或者用equals方法,或者自己定义一个compare方法,或者用getClass方法,但C语言里面比较只有地址值的比较,因此要实现类的标识相对就要困难一些。因此,这里定义了全局变量classClass,只要某个对象(obj_class变量)的objCore和classClass是相等的,那么它的类型就是obj_class(在vxworks中,类似的情形很多,例如标识文件的fpclass也是如此):
#define OBJ_VERIFY(objId,classId) \
( \
( \
(((OBJ_ID)(objId))->pObjClass == (struct obj_class *)(classId)) || \
( \
((OBJ_ID)(objId))->pObjClass && \
(((OBJ_ID)(objId))->pObjClass == \
(CLASS_ID)(((struct obj_class *)(classId))->initRtn)) \
) \
) \
? \
OK \
: \
(errno = S_objLib_OBJ_ID_ERROR, ERROR) \
)
obj_class结构体是所有其他vxworks结构体最基础的部分,要弄懂vxworks的实现原理,这个结构体及内存分配机制必须明白。vxworks代码十分精致,本人功力有限,仅能分析到这个地步,不过相信只要持续不停地努力,迟早能领悟其精髓。
0
0
0
来自CSDN博客:http://blog.csdn.net/efan_linux/archive/2009/11/13/4804760.aspx