C语言面向对象

2019/04/14 C语言 面向对象

本文主要想表达C语言设计也要有面向对象思想,但绝不是要去模拟面向对象语言本身。

简介

C语言一旦达到一定规模,就特别强调良好的架构设计,以保证代码的可读性、简洁以及可复用性。此时,软件设计者势必要用C语言来做面向对象的设计,我们可以看到Linux内核、驱动等大型的软件框架里面充满了面向对象的思想。

面向过程与面向对象

面向过程是以函数作为最基本的逻辑单元构建出来的整个业务系统。随着处理问题越来月复杂,实现业务的函数也越来越大,越来越多。不得不细化和归类函数,这便是模块化的思想。 但当处理问题的复杂程度超出了函数的能力范围,于是人们不得不开始考虑编程的基本单元。于是数据和算法的结合,对象就诞生了。

面向对象不是抛弃面向过程,而是在面向过程的基础上,把数据加入抽象的范畴。

相比面向过程,面向对象最主要的进化就是把问题领域中的事物给对象化了,对象包括属性和行为。在这个抽象的过程中,为了描述私有性,有了封装;为了描述传承性,有了继承;为了描述差异性,有了多态。

封装

封装的作用:隐藏细节,让代码模块化。

提炼数据结构

1551528325975

如上图所示是一个WAV文件的格式说明表,刚入门的人,可能就会通过指针偏移相应的字节数,然后来获取相应的成员信息。这样写出来的代码肯定很难读到,并且把数据和代码耦合到了一起。假如我们把表格提炼一个数据结构之后,会发现获取相应字段的信息变得非常方便。直接访问相对应的成员变量即可。而且改变也变得非常简单。提炼数据结构其实在我们平时的工程代码里面也是 随处可见的。

封装行为

实例分析

  1. 命令解析器(过程式设计)

面向过程设计的代码明显高耦合,要添加功能或修改某一个功能时会需要修改大部分内容。

面向对象设计:

面向对象的设计思想,把命令看成一个对象,将命令码和命令操作绑定到一起。提供一个统一的注册接口。这样设计代码后,很明显的gpio的代码更内聚了。cmd和其它模块之间的耦合性也降低了。新增其它模块也不需要修改已有代码了。

代码:https://github.com/lizhiduo/cmdManager

  1. 菜单(过程式设计)

如上图所示,是确认键和取消键的功能函数,但是对应的每一个菜单都会有不同的处理函数,每新增加一个菜单处理,就需要加一条switch-case。当菜单越来越多,就会有大量的switch-case代码去匹配具体的操作。

面向对象设计:

将按键看做一个对象,然后将属性和行为封装一起。避免了重复switch-case操作。

代码:https://github.com/lizhiduo/menu.git

继承

继承是指一个对象直接使用另一个对象的属性和方法。

目的是为了—代码重用。

继承这种代码重用手段,本质上是对象的重用,基本都发生在运行时;而程序设计中还有另外一个层次的重用,这个就是纯粹的源代码的重用,这个是发生在编译时候。这个就是泛型编程(这里不予讨论)。

C语言中如何达到类继承的这种作用?其实就是提炼软件中间层,其中间层的主要功能就是实现通用逻辑,对上统一接口,对下定义框架。linux里面大量使用了软件分层的思想。

实例分析:

linux的input子系统核心层主要实现了应用访问的file_operations接口,对输入设备驱动提供了一组注册和上报数据的接口(具体可以分析drivers/input/evdev.c)。

键盘驱动的数据流向:

1555213308843

多态

多态是同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时可以通过指向基类的指针,来调用派生类中的实现方法。

多态的目的—–接口重用

继承提供了复用,但是现实中个体往往存在差异性。多态就是用于在统一的接口这个框中描述个体的差异性。多态是继承这种手法的延续。

linux内核中同样是存在很多实例,主要是中间层通过判断底层是否实现相应行为(通过函数指针判断),未实现证明不特殊,使用中间层的统用逻辑即可(下图代码来自内核fbmem.c)。

Search

    Table of Contents