doubango是基于c語(yǔ)言的勋桶,所以采用一套特殊機(jī)制來(lái)模擬了類散罕。
類的聲明
typedef struct trtp_rtcp_header_s {
TSK_DECLARE_OBJECT;
//類自己的變量
}
trtp_rtcp_header_t;
如上圖挑随,用struct來(lái)模擬類状您,而在每個(gè)struct的開(kāi)始,添加TSK_DECLARE_OBJECT;
兜挨,然后是類自己的變量膏孟。
TSK_DECLARE_OBJECT
的作用是在每個(gè)類的開(kāi)始添加了3個(gè)變量。
__def__
是一個(gè)tsk_object_def_t結(jié)構(gòu)的指針拌汇,后面再講柒桑,
refCount
是一個(gè)引用計(jì)數(shù)。
lock
也是為了引用計(jì)數(shù)的一個(gè)鎖相關(guān)變量噪舀。
#define TSK_DECLARE_OBJECT \
const void* __def__; /**< Opaque data holding a pointer to the actual meta-data(size, constructor, destructor and comparator) */ \
volatile long refCount; /**< Reference counter. */ \
volatile long lock
類的創(chuàng)建
如何模擬類的構(gòu)造和析構(gòu)函數(shù)呢魁淳,這就要借助剛才提到的tsk_object_def_t飘诗。定義如下:
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;
tsk_object_def_t是一個(gè)類的描述,它包含了類的大小界逛,構(gòu)造函數(shù)昆稿,析構(gòu)函數(shù)函數(shù)和比較函數(shù)。每個(gè)類都會(huì)有一個(gè)tsk_object_def_t的全局變量息拜。如:
static const tsk_object_def_t trtp_rtcp_header_def_s = {
sizeof(trtp_rtcp_header_t),
trtp_rtcp_header_ctor,
trtp_rtcp_header_dtor,
tsk_null,
};
const tsk_object_def_t *trtp_rtcp_header_def_t = &trtp_rtcp_header_def_s;
有了它溉潭,就可以通過(guò)tsk_object_t* tsk_object_new(const tsk_object_def_t *objdef, ...)
構(gòu)造一個(gè)類了。
tsk_object_new 先通過(guò)def的size分配內(nèi)存少欺,初始化TSK_DECLARE_OBJECT增加的3個(gè)變量(對(duì)def賦值為傳入的objdef岛抄,設(shè)置引用計(jì)數(shù)為1),再通過(guò)def的構(gòu)造函數(shù)狈茉,對(duì)分配的內(nèi)存進(jìn)行初始化夫椭。
通常還會(huì)提供一個(gè)xxx_create或xxx_create_null
的函數(shù),來(lái)提供構(gòu)建的操作氯庆。 create
函數(shù)里調(diào)用tsk_object_new
來(lái)完成構(gòu)建蹭秋。
引用計(jì)數(shù)和銷(xiāo)毀
doubango里對(duì)象是通過(guò)引用計(jì)數(shù)來(lái)控制的,tsk_object_new
設(shè)置引用計(jì)數(shù)為1堤撵,如果對(duì)對(duì)象進(jìn)行了拷貝仁讨,并且要留下來(lái)做他用,需要調(diào)用tsk_object_t* tsk_object_ref(tsk_object_t *self)
來(lái)增加引用計(jì)數(shù)实昨。
不再需要時(shí)也通過(guò)tsk_object_t* tsk_object_unref(tsk_object_t *self)
減少引用計(jì)數(shù)洞豁。tsk_object_unref會(huì)檢查引用計(jì)數(shù),如果為0荒给,會(huì)自動(dòng)銷(xiāo)毀丈挟。因?yàn)閷?duì)象開(kāi)頭有ref指針,所以能找到析構(gòu)函數(shù)志电,調(diào)用析構(gòu)函數(shù)曙咽,并釋放內(nèi)存。
類的繼承
類的繼承在doubango里挑辆,是通過(guò)在子類struct的一開(kāi)始包含基類struct的變量來(lái)實(shí)現(xiàn)的例朱。基本語(yǔ)法如下:
//基類聲明
typedef struct tmedia_consumer_s
{
TSK_DECLARE_OBJECT;
//其他變量
} tmedia_consumer_t;
//為繼承積累定義一個(gè)宏鱼蝉,內(nèi)容為聲明一個(gè)基類的變量
#define TMEDIA_DECLARE_CONSUMER tmedia_consumer_t __consumer__
//子類繼承聲明
typedef struct tdav_consumer_audio_s
{
TMEDIA_DECLARE_CONSUMER;
//其他變量
}
tdav_consumer_audio_t;
由于基類變量是子類的第一個(gè)變量洒嗤,他們的地址是相同的,所以在使用時(shí)魁亦,直接對(duì)指針進(jìn)行強(qiáng)轉(zhuǎn)就可以了渔隶。(虛函數(shù)是沒(méi)有的)
虛類
以tdav_producer_audiounit_t
的繼承關(guān)系為例,如下:
tdav_producer_audiounit_t
繼承tdav_producer_audio_t
,tdav_producer_audio_t
又繼承tmedia_producer_t
吉挣。
你會(huì)發(fā)現(xiàn)派撕,tmedia_producer_t
并沒(méi)有提供_def_t的類,也沒(méi)有構(gòu)造和析構(gòu)函數(shù)睬魂。而是提供一個(gè)xxx_init
和一個(gè)xxx_uninit
函數(shù)终吼。由于沒(méi)有構(gòu)造析構(gòu)函數(shù)和def,所以無(wú)法實(shí)例化氯哮,模擬了虛類际跪。
子類的構(gòu)造函數(shù)里調(diào)用基類的xxx_init
和xxx_uninit
對(duì)基類部分進(jìn)行初始化和反初始化。
到此喉钢,對(duì)doubango的類結(jié)構(gòu)就基本了解了姆打。