繼承是面向對象軟件技術當中的一個概念,與多態、封裝共爲面向對象的三個基本特徵。繼承可使得子類具備父類的屬性和方法或者從新定義,追加屬性和方法。
面向對象中的重要概念就是類,在咱們熟知的編程語言 C++ 、Python 中都存在類的概念,經過現有的類從而繼承獲得新的類。可是對於 C 語言來說,其中並不存在類的概念,那又如何實現繼承呢 ?node
筆者瞭解到 C 語言實現繼承是在閱讀 rt-thread 源碼中發現的,rt-thread 以小而美的物聯網操做系統著稱,在閱讀其源碼的時候,也可以感覺到其實現的精妙,其中對於內核對象的管理就是以面向對象的方式進行,採用結構體嵌套的方式實現了內核對象的繼承與派生。在 rt-thread 的內核對象管理模塊中,定義了通用的數據結構 rt_object ,筆者在這裏姑且將其稱之爲父類,由於內核的線程對象,內存池對象,定時器對象,設備對象都是由 rt_object 派生而來。下面是 rt_object 的實現細節。編程
struct rt_object { char name[RT_NAME_MAX]; /**< name of kernel object */ rt_uint8_t type; /**< type of kernel object */ rt_uint8_t flag; /**< flag of kernel object */ rt_list_t list; /**< list node of kernel object */ };
有了這個通用數據結構,咱們就能夠依據此繼承派生出新的內核對象,好比定時器對象,其實現細節以下所示:數組
struct rt_timer { struct rt_object parent; /**< inherit from rt_object */ rt_list_t row[RT_TIMER_SKIP_LIST_LEVEL]; void (*timeout_func)(void *parameter); /**< timeout function */ void *parameter; /**< timeout function's parameter */ rt_tick_t init_tick; /**< timer timeout tick */ rt_tick_t timeout_tick; /**< timeout tick */ };
如上圖代碼所示,rt_timer 結構體內定義的 parent 就是由 rt_object 所繼承下來的,在繼承的基礎上,又在結構體內增長了新的內容,從而造成了定時器對象。
所以對於 rt_thread 中的線程對象,內存池對象,定時器對象也能夠用以下的一張圖代表他們之間的關係。數據結構
上述就是關於繼承的概念及 C 語言的具體的實現方式。編程語言
在 C++ 中對於容器的定義是這樣的:在數據存儲上,有一種對象類型,它能夠持有其餘對象或者指向其餘對象的指針,這種對象類型就是容器,對於 C++ 來講,有專門的構造函數實現容器,好比 vector() ,就能夠建立一個容器。函數
那 C 語言是如何建立一個容器呢 ?在 rt_thread 中,是經過一個全局數組的形式實現的,數組的類型是 rt_object_information ,rt_object_information 的實現代碼以下:ui
struct rt_object_information { enum rt_object_class_type type; /**< object class type */ rt_list_t object_list; /**< object list */ rt_size_t object_size; /**< object size */ };
其中,type 是用一個枚舉類型實現的,具體實現以下:操作系統
enum rt_object_info_type { RT_Object_Info_Thread = 0, /**< The object is a thread. */ #ifdef RT_USING_SEMAPHORE RT_Object_Info_Semaphore, /**< The object is a semaphore. */ #endif #ifdef RT_USING_MUTEX RT_Object_Info_Mutex, /**< The object is a mutex. */ #endif RT_Object_Info_Unknown, /**< The object is unknown. */ };
對象的鏈表是基於這樣實現的:線程
struct rt_list_node { struct rt_list_node *next; /**< point to next node. */ struct rt_list_node *prev; /**< point to prev node. */ };
因爲 rt_thread 中容器中的對象有點多,筆者將其中對象進行縮減,截取一部分出來,具體以下:3d
static struct rt_object_information rt_object_container[RT_Object_Info_Unknown] = { /* initialize object container - thread */ { RT_Object_Class_Thread, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread), sizeof(struct rt_thread) }, #ifdef RT_USING_SEMAPHORE /* initialize object container - semaphore */ { RT_Object_Class_Semaphore, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore), sizeof(struct rt_semaphore) }, #endif #ifdef RT_USING_MUTEX /* initialize object container - mutex */ { RT_Object_Class_Mutex, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex), sizeof(struct rt_mutex) }, #endif }
上面就實現了一個容器,其中_OBJ_CONTAINER_LIST_INIT 是一個宏定義,具體定義以下:
#define _OBJ_CONTAINER_LIST_INIT(c) \ {&(rt_object_container[c].object_list), &(rt_object_container[c].object_list)}
其所用是初始化對象的鏈表,將頭尾指針都指向自身,實現的效果以下:
因此整體來講,rt_thread 中實現的容器裏的內容就包含每個內核對象,而後內核對象是由一個結構體實現的,結構體包含着內核對象的類型,初始化好的內核對象鏈表以及內核對象的大小。既然如此咱們就能夠對容器裏的內容進行操做,好比得到指定內核對象的指針,代碼以下:
rt_object_get_information(enum rt_object_class_type type) { int index; for (index = 0; index < RT_Object_Info_Unknown; index ++) if (rt_object_container[index].type == type) return &rt_object_container[index]; return RT_NULL; }
經過 C 語言實現的繼承與派生,rt_thread 實現了多個內核對象的定義,而後經過 C 語言實現的容器,咱們能夠管理內核對象,容器中包含的內核對象有對象自己的鏈表,拿線程打比方,咱們新建立的線程也就能夠經過鏈表的形式掛接到容器中對應的線程控制塊中,實現的效果以下:
最後,若是您覺的個人文章對您有所幫助,能夠關注個人我的公衆號,期待與您一同前行~