继承的概念

继承是面向对象软件技术当中的一个概念,与多态、封装共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义,追加属性和方法。

面向对象中的重要概念就是类,在我们熟知的编程语言 C++ 、Python 中都存在类的概念,通过现有的类从而继承得到新的类。但是对于 C 语言来讲,其中并不存在类的概念,那又如何实现继承呢 ?

C 语言继承的实现

笔者了解到 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 语言容器的实现

那 C 语言是如何创建一个容器呢 ?在 rt_thread 中,是通过一个全局数组的形式实现的,数组的类型是 rt_object_information ,rt_object_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
}

上面就实现了一个容器,其中_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 语言实现的容器,我们可以管理内核对象,容器中包含的内核对象有对象本身的链表,拿线程打比方,我们新创建的线程也就可以通过链表的形式挂接到容器中对应的线程控制块中,实现的效果如下:

最后,如果您觉的我的文章对您有所帮助,可以关注我的个人公众号,期待与您一同前行~

C语言如何实现继承及容器的更多相关文章

  1. 模块的封装之C语言类的继承和派生

    [交流][微知识]模块的封装(二):C语言的继承和派生 在模块的封装(一):C语言的封装中,我们介绍了如何使用C语言的结构体来实现一个类的封装,并通过掩码结构体的方式实 现了类成员的保护.这一部分,我 ...

  2. C语言设计模式-封装-继承-多态

    快过年了,手头的工作慢慢也就少了,所以,研究技术的时间就多了很多时间,前些天在CSDN一博客看到有大牛在讨论C的设计模式,正好看到了,我也有兴趣转发,修改,研究一下. 记得读大学的时候,老师就告诉我们 ...

  3. django基础 -- 4. 模板语言 过滤器 模板继承 FBV 和CBV 装饰器 组件

    一.语法 两种特殊符号(语法): {{ }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 二.变量 1. 可直接用  {{ 变量名 }} (可调用字符串, 数字 ,列表,字典,对象等) ...

  4. [笔记]使用Go语言Redigo包在Docker容器内连接Redis容器的方法

    Docker容器之间的连接可以带来不少方便,下面记录下如何在自己容器内通过环境变量连接与之连接的Redis容器的方法. 先起一个Redis的Docker容器,命名为 redis,再起一个自己的Dock ...

  5. OOP3(继承中的类作用域/构造函数与拷贝控制/继承与容器)

    当存在继承关系时,派生类的作用域嵌套在其基类的作用域之内.如果一个名字在派生类的作用域内无法正确解析,则编译器将继续在外层的基类作用域中寻找该名字的定义 在编译时进行名字查找: 一个对象.引用或指针的 ...

  6. Django框架(十一):模板介绍、模板语言、模板继承、HTML转义

    1. 模板介绍 1.1 模板的功能 产生html,控制页面上展示的内容.模板文件不仅仅是一个html文件. 模板文件包含两部分内容: 静态内容:css.js.html. 动态内容:用于动态去产生一些页 ...

  7. C语言实现类似C++的容器vector

    C语言也能面向对象?不是C++是面向对象的么?其实C语言也能抽象成简单的面向对象方法,在Linux内核源码当中,底层的驱动代码.文件系统等皆采用了面向对象的封装技术,这样的好处是将客观的东西抽象出来, ...

  8. C++语言基础(9)-继承

    一.继承的基本语法 #include<iostream> using namespace std; //基类 Pelple class People{ public: void setna ...

  9. 《Java语言程序设计》继承与多态

    一.动手实验:继承条件下的构造方法 调用运行 TestInherits.java 示例,观察输出,注意总结父类与子类之间构造方法的调用关系修改Parent构造方法的代码,显式调用GrandParent ...

随机推荐

  1. 实验十一 MySQLl备份与恢复2

    实验十一 MySQL备份与恢复 一.  实验内容: 1. 使用SQL语句导入和导出表数据 2. 使用客户端工具备份还原数据库 3. 使用日志文件恢复数据库 二.  实验项目:学生成绩数据库 创建用于学 ...

  2. U - Inviting Friends HDU - 3244( LIS 最长升序子序列——变形 )

    序列变换 Problem Description 我们有一个数列A1,A2-An,你现在要求修改数量最少的元素,使得这个数列严格递增.其中无论是修改前还是修改后,每个元素都必须是整数. 请输出最少需要 ...

  3. Redis对象——列表(List)

    列表(list)类型是用来存储多个有序的字符串,列表中的每个字符串称为元素(element),一个列表最多可以存储232-1个元素.在Redis中,可以对列表两端插入(push)和弹出(pop),还可 ...

  4. [Vue warn]: Failed to mount component: template or render function not defined. found in ---> <XFbwz> at src/views/XFbwz.vue <App> at src/App.vue <Root>

    1.引入.vue文件忘记加.vue 2.引入文件内容为空

  5. Ring 笔记 - 核心概念

    Ring 是一个在 Clojure 中的对于 HTTP 的抽象,是构建 Web 应用的底层接口和库,类似于 Java 中的 Servlet 核心概念 Handler Handler 是一个定义web应 ...

  6. Spring (五):AOP

    本文是按照狂神说的教学视频学习的笔记,强力推荐,教学深入浅出一遍就懂!b站搜索狂神说或点击下面链接 https://space.bilibili.com/95256449?spm_id_from=33 ...

  7. MyBatis(九):动态SQL

    本文是按照狂神说的教学视频学习的笔记,强力推荐,教学深入浅出一遍就懂!b站搜索狂神说或点击下面链接 https://space.bilibili.com/95256449?spm_id_from=33 ...

  8. pip 命令参数以及如何配置国内镜像源

    文章更新于:2020-04-05 注:如果 pip 命令不可以用,参见:python pip命令不能用 文章目录 一.参数详解 1.命令列表 2.通用参数列表 二.实际应用 1.常用命令 2.`pip ...

  9. Docker多网卡

    # 查看所有网络 docker network ls # 如果要查看更加详细的虚拟网卡,如下指令 docker network inspect [NetWorkEthName | NetWorkEth ...

  10. uni-app的初识(01)

    1.什么是uni-app uni-app 是一个使用 Vue.js 开发所有前端应用的框架, 开发者编写一套代码, 可发布到IOS, Android, H5, 以及各种小程序(微信,百度)等多个平台. ...