C 語言如何實現繼承與容器

2021-02-19 wenzi嵌入式軟體

筆者能力有限,寫公眾號的目的主要是為了積累,同時也能夠激勵自己養成積累的習慣。如果文中有不對的地方,還請各位朋友能及時地給我指出來,我將不勝感激,謝謝~

繼承的概念

繼承是面向對象軟體技術當中的一個概念,與多態、封裝共為面向對象的三個基本特徵。繼承可以使得子類具有父類的屬性和方法或者重新定義,追加屬性和方法。面向對象中的重要概念就是類,在我們熟知的程式語言 C++ 、Python 中都存在類的概念,通過現有的類從而繼承得到新的類。但是對於 C 語言來講,其中並不存在類的概念,那又如何實現繼承呢 ?

C 語言繼承的實現

筆者了解到 C 語言實現繼承是在閱讀 rt-thread 源碼中發現的,rt-thread 以小而美的物聯網作業系統著稱,在閱讀其源碼的時候,也能夠感受到其實現的精妙,其中對於內核對象的管理就是以面向對象的方式進行,採用結構體嵌套的方式實現了內核對象的繼承與派生。在 rt-thread 的內核對象管理模塊中,定義了通用的數據結構 rtobject ,筆者在這裡姑且將其稱之為父類,因為內核的線程對象,內存池對象,定時器對象,設備對象都是由 rtobject 派生而來。下面是 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 */

};

如上圖代碼所示,rttimer 結構體內定義的 parent 就是由 rtobject 所繼承下來的,在繼承的基礎上,又在結構體內增加了新的內容,從而形成了定時器對象。因此對於 rt_thread 中的線程對象,內存池對象,定時器對象也可以用如下的一張圖表明他們之間的關係。

上述就是關於繼承的概念及 C 語言的具體的實現方式。

容器的概念

在 C++ 中對於容器的定義是這樣的:在數據存儲上,有一種對象類型,它可以持有其他對象或者指向其他對象的指針,這種對象類型就是容器,對於 C++ 來說,有專門的構造函數實現容器,比如 vector() ,就可以創建一個容器。那 C 語言是如何創建一個容器呢 ?在 rtthread 中,是通過一個全局數組的形式實現的,數組的類型是 rtobjectinformation ,rtobject_information 的實現代碼如下:

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 中容器中的對象有點多,筆者將其中對象進行縮減,截取一部分出來,具體如下:

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

}

上面就實現了一個容器,其中OBJCONTAINERLISTINIT 是一個宏定義,具體定義如下:

#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 語言實現的容器,我們可以管理內核對象,容器中包含的內核對象有對象本身的鍊表,拿線程打比方,我們新創建的線程也就可以通過鍊表的形式掛接到容器中對應的線程控制塊中,實現的效果如下: 

您的建議是對我的最大地提升,您的在看是對我最大的鼓勵

相關焦點

  • C語言實現繼承和多態
    下面就用純C自己寫一個簡單的類的繼承、多態。繼承 繼承大體是用派生類的第一個地址放置基類的對象,這樣我們用強轉也不會出現問題。print_child(struct _Parent *)} } c=4 } Child *ptr->print(ptr);//ptr0x013848c8 {a=1 b=2 print=0x003d65d4 {Test.exe!
  • C 語言面向對象編程 - 繼承
    – 封裝的簡單概念和實現。上一篇文章的具體內容,可以查看以下連結: C 語言面向對象編程 - 封裝本篇文章繼續來討論一下,如何使用 C 語言實現面向對象編程的一個重要特性:繼承。繼承就是基於一個已有的類(一般稱作父類或基類),再去重新聲明或創建一個新的類,這個類可以稱為子類或派生類。子類或派生類可以訪問父類的數據和函數,然後子類裡面又添加了自己的屬性和數據。
  • C語言實現面向對象的原理
    在性能不是很好、資源不是很多的MCU中使用C語言面向對象編程就顯得尤為重要。要想使用C語言實現面向對象,首先需要具備一些基礎知識。比如:(C語言中的)結構體、函數、指針,以及函數指針等,(C++中的)基類、派生、多態、繼承等。
  • C語言對象編程第二彈:繼承
    C語言對象編程的繼承與抽象。本次分享C語言對象編程第二彈:繼承。繼承簡單說來就是父親有的東西,孩子可以繼承過來。當創建一個類時,我們不需要重新編寫新的數據成員和成員函數,只需指定新建的類繼承了一個已有的類的成員即可。
  • 面向對象編程OOP的C語言實現
    解釋區分一下C語言和OOP我們經常說C語言是面向過程的,而C++是面向對象的,然而何為面向對象,什麼又是面向過程呢?不管怎麼樣,我們最原始的目標只有一個就是實現我們所需要的功能,從這一點說它們是殊途同歸的。過程與對象只是側重點不同而已。
  • 一步步分析:C語言如何面向對象編程
    這篇文章,我們就來聊聊如何在C語言中利用面向對象的思想來編程。也許你在項目中用不到,但是也強烈建議你看一下,因為我之前在跳槽的時候就兩次被問到這個問題。第二個問題:繼承繼承描述的是對象之間的關係,子類通過繼承父類,自動擁有父類中的屬性和行為(也就是方法)。這個問題只要理解了C語言的內存模型,也不是問題,只要在子類結構體中的第一個成員變量的位置放置一個父類結構體變量,那么子類對象就繼承了父類中的屬性。另外補充一點:學習任何一種語言,一定要理解內存模型!
  • C中的繼承和多態
    來自:吳秦 - 博客園作者:吳秦連結:http://www.cnblogs.com/skynet/archive/2010/09/23/1833217.html1、引言繼承和多態是面向對象語言最強大的功能
  • C語言實現複數運算
    今天給小夥伴們介紹下用C語言如何實現複數的運算,其實很簡單,但編程過程中封裝一下複數,並用宏做下處理會讓程序更加清晰明了,希望對小夥伴們有所幫助哈,!    實現時用結構封裝一下,並用宏處理下複數的實部和虛部,程序結構會變得更加清晰。        實際代碼如下,說明在注釋中了。
  • Spring 5 中文解析核心篇-IoC容器之BeanDefinition繼承與容器拓展點
    參考實例:com.liyong.ioccontainer.starter.XmlBeanDefinitionInheritanceContainer 1.8 容器拓展點 典型地,應用程式開發者不需要實現ApplicationContext類。相反,Spring IoC容器通過插件實現指定的集成接口去擴展。下面的章節描述這些接口的集成。
  • 真的可以,用C語言實現面向對象編程OOP
    解釋區分一下C語言和OOP我們經常說C語言是面向過程的,而C++是面向對象的,然而何為面向對象,什麼又是面向過程呢?不管怎麼樣,我們最原始的目標只有一個就是實現我們所需要的功能,從這一點說它們是殊途同歸的。過程與對象只是側重點不同而已。
  • TBOX | 一個用c語言實現的跨平臺開發庫
    數據的枚舉採用迭代器模型。目前支持sqlite3以及mysql兩種關係型資料庫,也可自定義擴展使用其他關係型資料庫。xml庫針對xml提供DOM和SAX兩種解析模式,SAX方式採用外部迭代模式,靈活性和性能更高,並且可以選擇指定路徑,進行解析。解析過程完全基於stream,所以是高度流化的,可以實現邊下載、邊解壓、邊轉碼、邊解析一條龍服務,使用較低的內存也可以解析大規模數據。
  • C語言如何實現動態擴容的string
    最近工作中使用C語言,但又苦於沒有高效的字符串實現,字符串的拼接和裁剪都比較麻煩,
  • ​如何使用容器實現生產級別的MongoDB sharding集群的一鍵交付
    如何使用容器技術來實現Mongo集群的一鍵式交付部署,屏蔽底層實現的細節,是很多人關心的話題。本文將給大家介紹基於進程的容器技術實現Mongo sharding集群的一鍵部署,充分展現了容器的強大威力。
  • C 語言實現Linux cp 命令
    小編今天介紹的項目課程就是教你用C語言來實現這個Linux cp命令,對C語言學習者來說是非常不錯的練手項目。項目名稱:【C 語言實現Linux cp 命令】項目簡介:該項目通過完成C 語言實現Linux cp 命令,掌握Linux作業系統中的文件IO相關的系統函數和目錄相關操作的系統函數,比如open, write, opendir, readir。深入了解Linux環境系統編程。
  • 深入理解Java繼承、封裝、多態的實現原理
    注意方法表條目指向的具體的方法地址,如 Girl 的繼承自 Object 的方法中,只有 toString() 指向自己的實現(Girl 的方法代碼),其餘皆指向 Object 的方法代碼;其繼承自於 Person 的方法 eat() 和 speak() 分別指向 Person 的方法實現和本身的實現。
  • C語言實操:用C語言實現隨機抽取紙牌
    利用數組實現從一副牌中隨機抽取紙牌,供大家參考,具體內容如下一、項目要求本程序負責發一副標準紙牌,每張標準紙牌都有一種花色
  • 70道C語言與C++常見問答題
    而C++的類的成員有這些訪問限定。C語言的結構體是沒有繼承關係的,而C++的類卻有豐富的繼承關係。「注意」:雖然C的結構體和C++的類有很大的相似度,但是類是實現面向對象的基礎。而結構體只可以簡單地理解為類的前身。
  • (五)C語言的變量、常量及運算
    2.1 了解常量的概念及使用方法常量的定義指在程序運行過程中不可改變的量,可以使用const用以描述一個存儲容器,使存儲容器不可變。這個不可變是種約束,當編譯器運行時,會檢查代碼,由於使用const對該量進行了描述,若該量嘗試發生改變時則會出現錯誤。現在編寫一段代碼,嘗試改變這個常量的值,查看會發生什麼。
  • 看穿容器的外表,Linux容器實現原理演示
    下面我們使用 C 語言和 Namespace 技術來手動創建一個容器,演示 Linux 容器最基本的實現原理。什麼是容器?容器其實是一種特殊的進程而已,只是這個進程運行在自己的 「運行環境」 中,比如有自己的文件系統而不是使用主機的文件系統(文件系統這個對我來說印象是最深刻的,也是讓人對容器很更好理解的一個切入點)。
  • C語言實現雙人猜數字遊戲
    點擊上方「學士科技」,選擇「設為星標」C語言合集(基礎、進階