doubango类面向对象研究
本来对面向对象理解就不深,拿到doubango的代码,感觉无从看起。
挑个通用的面向对象的实现的代码部分,来探究一下。比如,创建sip message的消息时,会调用tsip_message_create()函数,函数内容如下:
tsip_message_t* tsip_message_create() { return tsk_object_new(tsip_message_def_t, tsip_unknown); }
代码里面有两个重要部分,
1. tsip_message_def_t 是一个由sip模块自己定义的tsk_object_def_s对象。tsk_object_def_s是对象的统一的数据格式,里面必须有对象size,构造函数和析构函数:
typedef struct tsk_object_def_s { //! The size of the object. tsk_size_t size; //! Pointer to the constructor. tsk_object_t* (* constructor) (tsk_object_t *, va_list *); //! Pointer to the destructor. tsk_object_t* (* destructor) (tsk_object_t *); //! Pointer to the comparator. int (* comparator) (const tsk_object_t *, const tsk_object_t *); } tsk_object_def_t;
这其中sip自己定义的message对象为:
static const tsk_object_def_t tsip_message_def_s = { sizeof(tsip_message_t), tsip_message_ctor, tsip_message_dtor, tsk_null }; const tsk_object_def_t *tsip_message_def_t = &tsip_message_def_s;
2. 上面可以看出tsip_message_def_t是一个拥有构造函数和析构函数的对象,被传进tsk_object_new函数,这个函数的作用就是根据tsip_message_def_t来分配一块内存区域,并进行初始化。现在看一下tsk_object_new的具体内容:
tsk_object_t* tsk_object_new(const tsk_object_def_t *objdef, ...) { // Do not check "objdef", let the application die if it's null tsk_object_t *newobj = tsk_calloc(1, objdef->size); if(newobj){ (*(const tsk_object_def_t **) newobj) = objdef; TSK_OBJECT_HEADER(newobj)->refCount = 1; if(objdef->constructor){ va_list ap; tsk_object_t * newobj_ = newobj;// save va_start(ap, objdef); newobj = objdef->constructor(newobj, &ap); // must return new va_end(ap); if(!newobj){ // null if constructor failed to initialized the object tsk_free(&newobj_); } #if TSK_DEBUG_OBJECTS TSK_DEBUG_INFO("N∞ objects:%d", ++tsk_objects_count); #endif } else{ TSK_DEBUG_WARN("No constructor found."); } } else{ TSK_DEBUG_ERROR("Failed to create new tsk_object."); } return newobj; }
a. 代码第一行提示不用对objdef的防护。
b. 代码第二行根据之前传入的sip对象中的size来分配内存。
c. 代码第四行比较难理解。可以这样考虑,首先不要去想newobj是指向分配好的内存区域的指针,而是将它看作一个普通的void 指针。那么(const tsk_object_def_t **) newobj就会将newobj强制类型转换为一个tsk_object_def_t的指针,这个指针指向了一个tsk_object_def_t的指针。所以解引用newobj就写成*(const tsk_object_def_t **) newobj,它的结果就是tsk_object_def_t的指针。最后,将此指针指向objdef。
如下图所示,newobj为分配好的内存空间,经过(const tsk_object_def_t **) newobj转换之后,newobj的前4个字节,就变成了一个指向指针的指针,这个指针存储的内容是一个地址,这个地址后来被设置为objdef的地址,代码也就是地四行的(*(const tsk_object_def_t **) newobj) = objdef;
d. 第五行TSK_OBJECT_HEADER(newobj)->refCount将newobj的下一个位置设置为refCount,即引用计数,并初始化为1.
e. 第六行到十五行判断是否在对象中有默认构造函数,例如我们的sip message中构造函数为tsip_message_ctor,这个构造函数接受newobj参数,并将其初始化。