C语言 - 继承

我们知道C++ 的三大特性就是封装、继承、多态,同时这也是面向对象的重要特性,在这些特性的基础上我们在结合一些设计模式,这样我们的项目就变得高内聚,低耦合同时也增强了代码的安全性,可读性,可维护性。

我们在学习Linux内核代码的时候就会发现其实里面已经广泛利用C语言实现了这些特性,下面我们一起来学习一下怎么用C语言来实现这些面向对象的特性。

这一章我们先来聊聊继承,我们通过LED来举例,我们分别有3个LED,GPIO灯、PWM灯、I2C灯三个Struct抽出来我们发现会有很多是相似的,如图:

我们发现其中name、state是一模一样的,如果我们加入第四种,改一次name的逻辑,三个都要改,但凡是改漏一个就出现了bug,怎么办?

这时候我们把相同的部分抽出来,生成一个LedBase,然后放进其他3个struct,如下图

Struct里面放另一个Struct,就有点类似俄罗斯套娃,外层包着内层,有细心的小伙伴就发现了一个细节,公共部分都是放在了第一个位置,我们先来看看这样抽出来套娃后,在内存地址中是咋样的,如图

所以套娃后就是内存数据在前,外层数据紧跟其后连续排列,经过我们上面的改造后初始化也不用重复了,先初始化公众的再初始化模块的,如图

不只是数据,函数也是能共享的,例如我们要获取当前是哪个模块再使用,那么写了一个

const char *get_led_name(LedBase *me) {return me->name;}

我们通过如下调用:

get_led_name(&gpio_led.base);get_led_name(&pwm_led.base);get_led_name(&i2c_led.base);

在3个LED模块中调用这个get_led_name就会返回不同的名称, 这样三个LED都使用了同一个函数,写一次3种led都能用,只要传base的地址过去,函数其实不需要知道你是哪一种led。

在实践中我们会发现,继承不只是数据共享,行为也能共享,所以继承本质并不是为了少些代码,而是为了少改代码,只是在我们平时的使用过程中也要注意,在设计使用C的继承时,我们要把基础数据放在继承结构的首位,这样不管是数据强转、数据访问都不会有什么问题。