C函数指针别再停留在语法,得上升到软件设计

点击蓝字

a0ef8d122b950ce7f85bea44cf5cee63.png

关注我们

经常有朋友问到底如何在C程序中采用面向对象编程?如何让模块之间松耦合?......其实究其原因还是没有把C语言与软件设计很好的联系起来。这里跟大家找了一些内容,相信认真看完全文多多少少会有你想要的答案:

正文部分:

记得刚开始工作时,一位高手告诉我,说,longjmp和setjmp玩得不熟,就不要自称为C语言高手。当时我半信半疑,为了让自己向高手方向迈进,还是花了一点时间去学习longjmp和setjmp的用法。

后来明白那不单是跳来跳去那样简单,而是一种高级的异常处理机制,在某些情况下确实很有用。

为了显示自己的技巧,也在自己的程序中用过几次。渐渐发现这样的技巧带来的好处是有代价的,破坏了程序的结构化设计,程序变得很难读,尤其对新手来说。

终于明白这种技巧不过是一种调味料,在少数情况使用几次,可以简化对问题的处理。如果把调味拿来当饭吃,一定会本末倒置,写出的程序会呈现营养不良之状。

事实上,longjmp和setjmp玩得熟不熟与是不是C语言高手,不是因果关系。但是,如果可以套用那位高手的话,我倒想说如果函数指针玩得不熟,就不要自称为C语言高手。为什么这么说呢,函数指针有那么复杂吗?

当然不是,任何一个稍有编程常识的人,不管他懂不懂C语言,在10分钟内,我想他一定可以明白C语言中的函数指针是怎么回事。

原因在于,难的不是函数指针的概念和语法本身,而是在什么时候,什么地方该使用它。函数指针不仅是语法上的问题,更重要的是它是一个设计范畴。

真正的高手当然不单应该懂得语法层面上的技巧,更应该懂得设计上的方法。不懂设计,能算高手吗?怀疑我在夸大其辞吗?那我们先看看函数指针与哪些设计方法有关:与分层设计有关。分层设计早就不是什么新的概念,分层的好处是众所周知的,比较明显好处就是简化复杂度、隔离变化。

采用分层设计,每层都只需关心自己的东西,这减小了系统的复杂度,层与层之间的交互仅限于一个很窄的接口,只要接口不变,某一层的变化不会影响其它层,这隔离了变化。

分层的一般原则是,上层可以直接调用下层的函数,下层则不能直接调用上层的函数。这句话说来简单,在现实中,下层常常要反过来调用上层的函数。

比如你在拷贝文件时,在界面层调用一个拷贝文件函数。界面层是上层,拷贝文件函数是下层,上层调用下层,理所当然。但是如果你想在拷贝文件时还要更新进度条,问题就来了。

一方面,只有拷贝文件函数才知道拷贝的进度,但它不能去更新界面的进度条。另外一方面,界面知道如何去更新进度条,但它又不知道拷贝的进度。怎么办?

常见的做法,就是界面设置一个回调函数给拷贝文件函数,拷贝文件函数在适当的时候调用这个回调函数来通知界面更新状态。

与抽象有关。抽象是面向对象中最重要的概念之一,也是面向对象威力强大之处。面向对象只是一种思想,大家都知道,用C语言一样可以实现面向对象的编程。

这可不是为了赶时髦,而是一种实用的方法。如果你对此表示怀疑,可以去看看GTK+、linux kernel等开源代码。

接口是最高级的抽象。在linux kernel里面,接口的概念无处不在,像虚拟文件系统(VFS),它定义一个文件系统的接口,只要按照这种接口的规范,你可以自己开发一个文件系统挂上去。

设备驱动程序更是如此,不同的设备驱动程序有自己一套不同的接口规范。在自己开发设备开发驱动程序时,只要遵循相应的接口规范就行了。接口在C语言中如何表示?很简单,就是一组函数指针。

与接口与实现分开有关。针对接口编程,而不是针对实现编程,此为《设计模式》的第一条设计准则。分开接口与实现的目标是要隔离变化。软件是变化的,如果不能把变化的东西隔离开来,导致牵一发而动全身,代价是巨大的。这是大家所不愿看到的。

C语言既然可以实现面向对象的编程,自然可以利用设计模式来分离接口与实现。像桥接模式、策略模式、状态模式、代理模式等等,在C语言中,无一不需要利用函数指针来实现。

与松耦合原则有关。面向过程与面向对象相比,之所以显得苍白无力,原因之一就是它不像面向对象一样,可以直观的把现实模型映射到计算机中。

面向过程讲的是层层控制,而面向对象更强调的对象间的分工合作。现实世界中的对象处于层次关系的较少,处于对等关系的居多。也就是说,对象间的交互往往是双向的。这会加强对象间的耦合性。

耦合本身没有错,实际上耦合是必不可少的,没有耦合就没有协作,对象之间无法形成一个整体,什么事也做不了。关键在于耦合要恰当,在实现预定功能的前提下,耦合要尽可能的松散。这样,系统的一部分变化对其它部分的影响会很少。

函数指针是解耦对象关系的最佳利器。Signal(如boost的signal和glib中的signal)机制是一个典型的例子,一个对象自身的状态可能是在变化的(或者会触发一些事件),而其它对象关心它的变化。一旦该对象有变化发生,其它对象要执行相应的操作。

如果该对象直接去调用其它对象的函数,功能是完成了,但对象之间的耦合太紧了。如何把这种耦合降到最低呢,signal机制是很好的办法。

它的原理大致如下:其它关注该对象变化的对象主动注册一个回调函数到该对象中。一旦该对象有变化发生,就调用这些回调函数通知其它对象。功能同样实现了,但它们之间的耦合度降低了。

在C语言中,要解决以上这些问题,不采用函数指针,将是非常困难的。在编程中,如果你从没有想到用函数指针,很难想像你是一个C语言高手。

*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

6873521152aec1cf0462344f98207684.png

73bb784f5cc84c0eb39b251b3e17a498.gif

戳“阅读原文”我们一起进步

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337621.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring默认缓存管理器_使用Spring的缓存管理器缓存Web内容

spring默认缓存管理器在这篇文章中,我想向大家展示如何使用Spring的CacheManager, Cacheable和JMX批注来缓存和管理Web内容的缓存的基础知识。 想象一下一个网上商店,它从远程WCMS(Web内容管理系统)获取一些内容&#…

计算机软件选修课选什么好,大学值得选的“选修课”,一点不比专业课差,能选上最好认真听...

原标题:大学值得选的“选修课”,一点不比专业课差,能选上最好认真听文/小哈你是怎样对待你的选修课的?以前经常听学长学姐们说过这样一句话,“上大学之后,专业课选逃,选修课必逃”。不知道大家是…

C/C++程序员的编程修养

点击蓝字关注我们什么是好的C/C程序员?是不是懂得很多技术细节?还是懂底层编程?还是编程速度比较快?我觉得都不是。对于一些技术细节来说和底层的技术,只要看帮助,查资料就能找到,对于速度快&am…

python账号密码一一对应_python模拟用户登录系统,如何两个用户输入各自的密码才能登入?...

展开全部 #我可以把我自己2113的成果送你,你来研究5261研究 import json #用来存储数据4102的模块 import os #用来进行文件操作1653 import sys #获取脚本所在目录用 import re #用来进行字符串操作 script_path os.path.realpath(__file__) PATH os.path.dirnam…

C语言#define与typedef的区别

点击蓝字关注我们在C语言编程中,typedef 和 #define是最常用语句,可能很多工作过几年的工程师都没有去深究过它们的一些用法和区别。typedef的用法在C/C语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部…

html文字添加波浪线,利用css渐变给文字下方加波浪线

具体代码如下.wavy-line-decoration {position: relative;line-height: 1.5em;}.wavy-line-decoration::before {content: ;position: absolute;bottom: -3px;width: 100%;height: 0.25em;background: // 可以给同一个元素同时添加多个背景渐变图层,用逗号隔开&…

新旧C++生成随机浮点数方法,你喜欢哪个?

点击蓝字关注我们一、在C11之前,我们通常采用rand函数来生成随机数。有时我们想用rand生成一组随机数,即使我们调用了srand,但生成的还是相同值。为什么会产生这种情况?又该如何解决?下面将用第一视角一起探究这其中的…

html页面加载完成后会触发的事件_前端隐秘角落 - 页面渲染

前言如图所示,webkit内核浏览器的渲染过程(解析HTML,构建DOM树,解析CSS,构建CSSOM树 ,构建render树,布局layout,绘制painting),这些过程理解起来可能有些抽象,今天我们一…

计算机进管理提示找不到入口,win10系统开机提示xxxdll模块已加载但找不到入口点的教程...

有关win10系统开机提示xxxdll模块已加载但找不到入口点的操作方法想必大家有所耳闻。但是能够对win10系统开机提示xxxdll模块已加载但找不到入口点进行实际操作的人却不多。其实解决win10系统开机提示xxxdll模块已加载但找不到入口点的问题也不是难事,小编这里提示两…

十大经典排序,你真的都会了吗?(源码详解)

点击蓝字关注我们一、前言:排序的概念排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。稳定性:假定在待排序的记录序列中,存在多个具有相同的关键…

jvm 架构_不可变的基础架构,热部署和JVM

jvm 架构您是否在生产中部署和取消部署基于JVM的应用程序(无论JVM容器/无容器)? 也就是说,当您拥有某个应用程序或服务的新版本时,是否通过“取消部署”和“热部署”该应用程序的新更新版本来更改正在运行的JVM&#x…

c语言默认参数_5.1 C++有默认参数的函数

点击上方“C语言入门到精通”,选择置顶第一时间关注程序猿身边的故事作者闫小林白天搬砖,晚上做梦。我有故事,你有酒么?C有默认参数的函数在函数调用时形参从实参获取值,因为实参的个数要和形参相同,但有时…

计算机组成原理唐朔飞课后答案第六章,计算机组成原理第六章部分课后题答案(唐朔飞版)...

计算机组成原理第六章部分课后题答案(唐朔飞版) 6.4 设机器数字‎长为8位(含1位符号‎位在内),写出对应下‎列各真值的‎原码、补码和反码‎。 -13/64,29/128,100,-87 解:十进制数 二进制数 原 码 反 码 补 码 -13/64 …

jboss eap 7.0_是时候抛弃Java 7 – JBoss EAP 6.4了!

jboss eap 7.0这一周真是太棒了。 JBoss EAP 6.4已发布,在众多技术增强和新功能中 ,最大的是:Java 8已添加到受支持的配置列表中。 其中包括Oracle JDK和IBM JDK。 Java SE 7公开更新结束通知 2015年4月之后,Oracle将不再将Java …

C语言史上最愚蠢的BUG ???

点击蓝字关注我们本文来自“The most stupid C bug ever”,很有意思,分享给大家。我相信这样的bug,就算你是高手你也会犯的。你来看看作者犯的这个Bug吧。。首先,作者想用一段程序来创建一个文件,如果有文件名的话&…

python 字符串转日期_我总结的130页Python与机器学习之路V1.2.pdf,都是干货!

告别枯燥,通过学习有趣的小例子,扎实而系统的入门Python,从菜鸟到大师,个人觉得这是很靠谱的一种方法。通过一个又一个的小例子,真正领悟Python之强大,之简洁,真正做到高效使用Python.两周前发出…

大学计算机需要论文吗,大一新生刚开学,是否有必要带电脑?听听辅导员的建议,非常中肯...

原标题:大一新生刚开学,是否有必要带电脑?听听辅导员的建议,非常中肯各大高校的录取工作正在如火如荼的进行,很快考生们就能接到来自各个学校的录取通知书。对于考生来说,没有什么事情会比被心仪的大学录取…

计算机系统是连续系统,连续系统的计算机模拟

连续系统的计算机模拟 (36页)本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!29.9 积分 第2章 连续系统的计算机模拟本章讨论连续系统的模拟技术,由于这类系统中状态随时间连续动态地变化&…

ae合成设置快捷键_教程|AE教程第三波:必须掌握的关键帧之基础设置

该如何高效的学习AE?星驰君认为知其然还需知其所以然正确的学习顺序应该是了解核心原理,掌握基本操作,案例实战模仿比如,想要更好的掌握和运用关键帧来制作更复杂的效果。就先要知道关键帧是什么关键帧:计算机动画术语…

老兵精讲:高质量C语言编程的10条规范

点击蓝字关注我们C语言编码规范10条分享给大家,还是可以规避掉很多bug的!1、最重要的规则编写代码时最重要的一条规则是:检查周围的代码并尝试模仿它。作为维护人员,如果收到的补丁明显与周围代码的编码风格不同,这是令…