什么是 C 语言面向对象?
在开始嵌入式 C 语言设计模式系列文章之前,先通过三篇文章讲述了如何使用 C 语言实现面向对象的三大特性,封装,继承,多态。
对于“面向对象”这个词语,相信很多软件工程师都不会感觉到陌生,并且很多软件工程师在刚开始学习编程的时候,讲师一般都会跟我们讲,C 语言是一门面向过程的语言,而 C++,Java,Python,Go 等高级语言,才是主流的面向对象语言。
那到底什么是“面向过程”,什么是“面向对象”呢?关于这两者的概念,我相信网络上并不缺少相关的信息,这里也不再复制粘贴网上的概念介绍。
举几个例子:
例子1:
客户:“我需要一份蛋炒饭”。
面向过程:先把饭煮好,点火起锅烧油,鸡蛋先放,炒好捞出,再起锅烧油,瘦肉豆芽胡萝卜丝翻炒半熟捞出,刷锅起锅烧油,倒入米饭。。。。一顿操作猛如虎。
面向对象:蛋炒饭有米饭,鸡蛋瘦肉豆芽胡萝卜丝,需要花生油,炒锅,等等工具,需要厨师,需要。。。。
例子2:
客户:“我需要一辆自行车”。
面向过程:先把自行车的机架车身电焊,上油漆,再安装前后两个车轱辘,安装刹车,安装停车支架,安装扶手,安装坐垫,安装篮子。。。
面向对象:自行车有机架车身,有车轱辘,有刹车,有停车支架,有扶手,有坐垫,有篮子,刹车用来刹车(这话有点废,哈哈哈),车轱辘用来行走。。。
例子3:
客户:“我需要一架航天飞机”。
面向过程:先找来一些耐高温耐辐射的航天级工业材料,用来打造航天飞机的机身,机身主要分为前段机身、中段机身和后段机身,各段机身打造完成后,开始设计机身内部航天员活动空间,然后再设计主发动机和轨道控制发动机,然后再。。。。(编不下去了)
面向对象:找NASA。(开玩笑,哈哈哈哈)
如上面三个(其实是前两个)例子所述,面向过程主要思考的是“如何(HOW)”的问题,也就是把一个目标,拆分为多个流程环节,然后把每个流程环节拼凑起来,最终实现客户想要的目标。
而面向对象,主要思考的是“什么(WHAT)”的问题,面向对象会先把一句具体的目标拆分,目标里面包含什么,每一个“什么”各自能完成哪些功能,把这些一个个的“什么”拼凑起来,就可以实现客户想要的目标。
面向过程的思维,和面向对象的思维,有着本质上的区别,一直从事嵌入式开发的工程师,特别是单片机工程师,在面对销售业务提出的需求或者疑问的时候,多数都是采用面向过程而非面向对象的思维方式进行思考。
也就是说,单片机工程师第一反应,是想着“如何(HOW)”去解决业务端的需求,而不是去深挖这个需求的本质是“什么(WHAT)”。
很多嵌入式C语言的入门教程,以及网络上大多数的开发示例,都是用“HOW”的思维方式去告诉我们怎么解决一个问题,很少用“WHAT”的思维去让工程师们思考问题的本质。
(注意:这里并不是在否定面向过程的优势之处!)
“HOW”的思维模式跟 C 语言的语法有着很大的关系,因为基于 C 语言的语法实现面向对象,会绕一些弯路,C 语言的语法没有面向对象的语法糖支持,所以用 C 语言实现面向对象会有一定的困难。
但往往在一些业务复杂的场景下,使用“WHAT”的思维比使用“HOW”的思维更加凑效,更能反映问题的本质,再往更深层次的思考,就会去到“WHY”的层面了。
编程语言只是一种工具,而“面向对象”和“面向过程”是两种编程思想,编程思想会指导嵌入式工程师如何使用程序语言工具,这就是 C 语言和面向对象的本质。
为什么要用 C语言面向对象?
既然面向对象是一种编程思想,而编程语言只是一种工具,那么,思想与工具之间就不存在一种强耦合的关系,C++可以面向对象,Java可以面向对象,C 语言同样可以面向对象。
现在很多嵌入式设备的处理器,都可以支持使用 C++ 语言进行开发,但对于以往惯用的开发方式,嵌入式设备还是用 C 语言开发居多。
一些业务简单,逻辑不复杂的嵌入式设备或嵌入式软件模块,其实是可以直接使用“面向过程”的思维模式去进行开发,这样最直接高效,对于初学者,也建议用“HOW”的方式去进行入门。
而一些复杂的业务场景,比如,操作系统内核,协议栈,通用的驱动模块,等等,就不得考虑使用面向对象“WHAT”的思维方式去思考和设计了。
因为像操作系统、协议栈这些复杂的业务模块,所面对的场景是很丰富而且很复杂的,面向过程的思维就会让这些业务模块在设计和使用的时候受限。
这些运行在嵌入式设备里面的业务模块,为了执行效率,通常都是用 C 语言进行开发的,所以,就不得不用C语言进行面向对象开发。
关于C 语言面向对象的争议
用 C 语言进行面向对象开发,在嵌入式工程师群体里面,一直都存在着争议,并且这个争议维持了很长一段时间,都没有得出正确的结论,并且群里面的小伙伴有时候会为这个话题争论得面红耳赤。
有些工程师认为,既然嵌入式设备要进行面向对象设计,为啥不用 C++ 语言,或者用 Rust 语言,这些语言岂不是支持更多面向对象的语法特性,因为这些语言的语法支持面向对象,使用起来岂不是更加简单?
也有一些工程师认为,既然一些规模比较大的芯片厂家提供的 SDK,基本上都是使用面向对象进行框架设计,还有世界上最优秀的开源操作系统 Linux,里面也大量使用了 C 语言面向对象来设计驱动框架,
那么,作为嵌入式软件工程师,并且主要使用的编程语言是 C 语言,就更需要学习如何使用 C 语言面向对象的方式,去应对复杂庞大的业务需求,设计出高弹性可扩展的业务框架。
笔者认为,不管“面向过程”还是“面向对象”,不管是 C 语言还是其他高级语言,其本质都是解决业务问题的工具,除了要学习如何使用这些工具,还需要学习如何选择合适的工具去解决特定的问题。
编程思维没有高低优劣之分,编程语言更是如此,因为这些编程思维和编程工具,都是在特定场景下,解决特定问题的工具。
网络上经常会看到很多人拿 C 语言去跟其他语言比较,说某某语言将会被淘汰,不建议再学习,某某语言天下第一YYDS,等等。
且不说是不是有人别有用心,为了噱头而抛出这些话题,光是这种片面的对比,就知道这些人的论点和论据过于片面而经不起事实的推敲,参与这些话题的争论,最终只会浪费自己的时间。
最后,本系列文章需要强调一个基本原则,就是:不是所有使用C语言开发的嵌入式软件,都一定要用面向对象的思维进行编码指导,也并不是否定C语言面向过程开发的优势之处。一名优秀的嵌入式软件工程师,需要学会根据实际的项目情况,合理地选择编程语言和编程思维,才能创造出稳定可靠,高内聚低耦合,高弹性易扩展的应用软件。