关闭

用C实现C++的多态---剖析GTK的"对象" (二)

1116人阅读 评论(0) 收藏 举报

四. 如何构造一个对象
    我们用下面的结构来描述一个对象:
    typedef struct _ClassType
    {
        char* name; /*对象名,唯一*/
        int   object_size;/*对象大小,创建实列时分配内存要用到*/
        int   class_size; /*全部虚函数大小,如sizeof(CObjectClass)*/
        void* vclass; /*虚函数指针*/
        void (*InitClassCallback)(void*); /*给对象的虚函数赋值*/
        void (*InitObjectCallback)(void*);/*对象实例化时,给实例成员赋初值,有点类似构造函数*/
        struct _ClassType*  parent; /*父对象*/
        struct _ClassType*  next; /*单向链表,指向下一对象*/
    }ClassType;
   
    #define [MAX_CLASS_NUM 128
    static ClassType classes[MAX_CLASS_NUM]; /*对象池*/
    static ClassType *used_classes = NULL;
    static ClassType *free_classes = NULL;
    这里只定义了128个对象,数目可能修改或者改成动态分配。

    初始化,全部链接到空闲链表中。
    void InitObjectLib(void)
    {
        int i;
        memset(classes, 0, sizeof(ClassType)*MAX_CLASS_NUM);
        for( i=0;i<MAX_CLASS_NUM-1;i++ )
        {
            classes[i].next = &(classes[i+1]);
        } 
        free_classes = &(classes[0]);
    }

    这个函数既是获取对象的虚函数指针,也是注册对象。
    这里要注意type为static,一个对象只注册一次,下次获取时直接取type。
    RegisterClassType()第一个参数为对象的描述信息,第二个参数为父对象的
    函数指针,我们来看一下它的定义:
    #define TOP_OBJECT_TYPE 0
    #define BASE_OBJECT_TYPE GetObjectType()
    因为CObject为基对象,它没有父对象,所以这里第二个参数为0(TOP_OBJECT_TYPE)。
    现在假设有一个CObject子对象CSubObject,那么注册它时应该这样写:
    type = RegisterClassType(&classinfo, BASE_OBJECT_TYPE);
    由此可能看到,这里其实是一个递归:当注册CSubOject里会用到参数BASE_OBJECT_TYPE,
    既GetObjectType(),这样就可以把CObject也注册上。
    简单的说:如果C继承于B,B继承于A,现在假设A、B还未注册,当注册C时,通过递归
    也能把B、A注册上。

    int GetObjectType(void)
    {
        static int type = 0;

        if( type==0 )
        {
            static ClassInfo classinfo =
            {
                "OBJECT", /*对象名,唯一*/
                sizeof(CObject),
                sizeof(CObjectClass),
                (pInitObjectCallback)InitObject,
                (pInitClassCallback)InitObjectClass,
            };

            type = RegisterClassType(&classinfo, TOP_OBJECT_TYPE);
 }

        return type;
    }

    我们再来看一看InitObject和InitObjectClass,
    static void InitObjectClass(CObjectClass *vclass)
    {
        if(vclass==NULL)
            return;
        vclass->destory = DestoryObject;/*对虚函数赋值*/
    }

    static void InitObject(CObject *object)
    {
        if(object==NULL)
            return; 
        object->ref_counter = 1;
    }

    这两个函数在GetObjectType()被传进去,那么又是在哪儿被调用的呢?
    让我们看RegisterClassType()
    int RegisterClassType(ClassInfo *classinfo, int parent_type)
    {
        int type = 0;
        ClassDesc *current, *parent;

        parent = (ClassType *)parent_type;

        if( classinfo->name==NULL )
        {
            TRACE("RegisterClassType(): class name is NULL/n");
            return type;
        }
        /*检查是否有对象名重复*/
        current = used_classes;
        while(current)
        {
            if(strcmp(current->name, classinfo->name)==0 )
            {
                TRACE("RegisterClassType(): class name is redefined/n");
                unlock();
                return type;
            }
            current = current->next;
        }

        /*创建对象*/
        current = free_classes;
        if(current)
        {
            free_classes = free_classes->next;
            current->name = classinfo->name;
            current->parent = parent;
            current->class_size = classinfo->class_size;
            current->InitClassCallback = classinfo->InitClassCallback;
            current->InitObjectCallback = classinfo->InitObjectCallback;
            current->vclass = malloc(current->class_size);
            if( current->vclass==NULL )
            {
                TRACE("RegisterClassType(): malloc vclass failed/n");
            }
            memset( current->vclass, 0, current->class_size);
            current->vclass->class_type = (int)current;
            if( parent )/*子对象的虚函数全部指向父对象的虚函数*/
            {
                memcpy(current->vclass, parent->vclass, parent->class_size);
            }
            对子对象新添加的虚函数赋值,也可以对继承于父对象的虚函数重赋值。
            if( current->InitClassCallback )
                current->InitClassCallback(current->vclass);
            链接到对象池中
            current->next = used_classes;
            used_classes = current;
        }
        else
        {
            TRACE("RegisterClassType(): ERROR, no class in class pool/n");
        }
 
        type = (int)current; 注意:type为ClassType类型的指针。
        return type;
    }

   
五. 创建对象的实例

 CObject *NewObject(void) /*创建一个实例*/
 {
  return NewClassType(BASE_OBJECT_TYPE);
 }

 void *NewClassType(int class_type)
 {
  ClassType *pclass = NULL;
  void *object = NULL;

  if( pclass==0 )
   return NULL;
 
  pclass = (ClassType*)class_type;
  /*为实例分配内存空间*/
  object = (CObject*)malloc(pclass->object_size);
  if( object )
  {
   /*实例的虚函数指针指向它的对象的虚函数指针*/
   ((CObject*)object)->vclass = pclass->vclass;
   /*调用父对象的初始化函数,这个函数是递归函数,
   先初始化基对象,再初始化子对象,再初始化子子对象...*/
   InitParentObject(pclass, object);
  }

  return object;
 }

 static void InitParentObject(ClassType *current, void *object)
 {
  if( current )
  {
   if( current->parent )
    InitParentObject(current->parent, object);
   if( current->InitObjectCallback )
    current->InitObjectCallback(object);
  }
 }


 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:42939次
    • 积分:625
    • 等级:
    • 排名:千里之外
    • 原创:17篇
    • 转载:2篇
    • 译文:0篇
    • 评论:6条
    最新评论