聚会
C 语言春节回家过年, 遇到了不少小伙伴: Java , Python, JavaScript,Ruby......
大家在大城市发展得都不错, 回到老家, 聚到一起吃饭, 谈天说地, 都是喜气洋洋.
尤其是 Python 和 JavaScript, 更是成了明星, 一个吹嘘说自己是人工智能的必备, 另外一个炫耀说自己是世界上最流行的语言, 不信有某某语言流行度排行榜为证, 还有 GitHub 上的众多项目云云.
老练的 Java 则是一直拿 TIOBE 排行榜说事儿:"我已经连续 10 多年排行第一了, 高处不胜寒啊!"
提到 TIOBE,Python 更是得意:"我今年还被选为 TIOBE 的年度编程语言呢!"
虽然常年排名 TIOBE 第二, C 语言有点黯然神伤, 人类用自己写的程序可真不少, 可都是处于底层, 在系统级编程, 操作系统, 数据库, 编译器等, 与应用层比起来, 没那么光鲜亮丽.
现在很多人培训了 Python,Java 就说自己会编程了, 不懂指针, 不懂内存, 不懂底层的基本原理, 那能算会编程吗?
C 语言开始愤愤不平, 闷头吃菜, 似乎要把这股郁闷之气发泄到美味佳肴上去.
觥筹交错之间, Java 搂住 C 的肩膀, 亲切地说:"兄弟, 你有对象了吗?"
这下可捅了马蜂窝, 大家的眼光齐刷刷地聚集到 C 语言的身上.
C 嚅嗫了半天:"没, 没有."
"哈哈哈! 我们都有对象, 你这么大了还没对象?!" Python 笑道.
"是啊, 一个没有对象的编程语言还有什么前途?" JavaScript 补刀, 他原来没有 class 的概念, 是通过 "原型" 实现的 OOP, 最近几年才在语法层面引入 class 关键字.
"我虽然没有对象, 但是有指针啊, 功能非常强大."
"指针? 你说的是那容易出错的指针吗? 现在有谁用指针啊?" JavaScript 说道.
"不会用指针, 就不是真正的程序员!" C 语言涨红了脸.
餐桌的气氛变得有些尴尬, 捅了篓子的 Java 招呼着说:"来来来, 继续喝酒."
好不容易熬到聚餐结束, C 语言回到了自己的家, 家里冷冷清清, 自己的 "亲爹" 丹尼斯. 里奇(Dennis Ritchie), 有史以来最伟大的程序员之一, 已经于 2011 年 10 月不幸去世.
如果有想要学习 C/C++ 的小伙伴, 可以关注小编[C/C++ 企鹅群 374890319] ,wx 公众号: CPP_cx 小编也有 5 年编程经验了, 免费送一套比较系统的资料, 教程和工作经验, 就当是福利吧! 21 天速成加 QQ 群: 374890319
桌子上摆着的一本《C 程序设计语言》, 那是丹尼斯. 里奇唯一的遗著, 拿起这本书, C 不由悲从心来.
串门
C 语言突然想起来对门的 Ken Thompson, 那是 Dennis Ritchie 的 "好基友", 他们俩一起创造了伟大的 Unix 操作系统, 获得了计算机界的最高奖: 图灵奖.
要不问问 Ken ? 为什么不让我有对象? 不让我面向对象编程!
C 来到 Ken Thompson 的门口, 按了门铃. 门开了, C 语言一眼就看到 Ken Thompson 正在和 Go 玩得不亦乐乎, 心中更是凄苦, Go 才是人家的亲儿子, 我算老几, 转身便要离去.
Ken 却从后面叫住了他:"小 C 啊, 快进来, 和你的兄弟 Go 玩一会儿."
看到 C 满脸沮丧, Ken 也大为吃惊:"大过年的, 怎么回事?"
C 不满地说:"当年你们为什么不让我有对象?"
"对象, 什么对象? 奥, 你是说面向对象编程吧! 其实你亲爹把你设计出来, 主要是做系统级编程的, 要的是贴近硬件, 要的是效率, 要那复杂玩意儿干啥? 中看不中用, 再说了, 你和 Go 一样, 不是有 struct 吗?" Ken 转向 Go , 挤了挤眼睛.
"是啊是啊, struct 很好用的!" Go 马上附和.
"但是 struct 也实现不了 OOP, Python,JavaScript 他们都嘲笑我!"
"那你说说, 什么是 OOP ?" Ken 问道.
"封装, 继承, 多态吧?" C 回答到.
"好, 我来给你掰扯掰扯, 用 C 语言怎么实现封装, 继承还有多态!"
封装
Ken Thompson 迅速就写了一段代码. 他说:"我们先来说说封装, 这封装就是把信息给隐藏起来, 你先看看这段代码."
shape.h
shape.c
main.c
这里定义了一个叫做 Shape 的结构体, 外界只能通过相关的函数来对这个 Shape 进行操作, 例如创建 (Shape_create), 移动(Shape_move), 还有获取位置(Shape_getX) 等, 不能直接访问 Shape 的内部数据结构.
虽然这里没有 class 这样的关键字, 数据结构和相关操作是分开写的, 看起来不太完美, 但确实是实现了封装.
C 看到 Ken Thompson 居然把那个指针的名称叫做 self, 和 Python 的相同, 不由得笑了起来:"我明白了, 那继承该怎么做呢?"
继承
Ken Thompson 不吭声, 继续写代码:
这次定义了一个矩形 (Rectangle) 的结构体, 其中嵌套了 Shape, 难道这就实现了继承? C 有点疑惑.
Go 小子在旁边叫了起来:"我明白了, 在内存中, 他们是这样的."
通过这种组合的方式, 也算是实现了继承吧.
多态
这么轻松就实现了封装和继承, C 语言感到很兴奋, 但是多态怎么实现呢?
这时候又传来了门铃声, Linus 大神拎着一瓶酒进来, 要找 C 小伙儿喝酒, 看到这桌子上的代码, 立刻就明白了怎么回事.
他说道:"别整那么多花里胡哨的东西, 还多态, 不就是函数指针嘛! 我给你举个例子."
- "这个结构体包含了两个函数指针, 一个用来计算图形的面积, 另外一个把这个图形画出来. 我们把这个结构体叫做虚函数表."
- "这有什么用啊?"
"在你的 Shape 中, 添加一个指向该函数表的指针就行了." Linus 回答.
C 和 Go 都是一脸茫然.
"你们想想啊, 当你创建一个子类对象的时候, 比如 Rectangle, 把那个虚函数指针 vptr 指向另外一组函数, 会怎么样?"
两人还是不懂, Linus 只好继续画图:
现在 C 有点明白了, 无论是 Rectangle 对象, 还是 Square 对象, 在调用 Shape_area 方法的时候, 都需要通过 vptr 这个指针找到虚函数表中的 area 方法, 对于 Rectangle, 找到的是 Rectangel_area 方法, 对于 Square, 找到的是 Square_area 方法.
如果有想要学习 C/C++ 的小伙伴, 可以关注小编[C/C++ 企鹅群 374890319] ,wx 公众号: CPP_cx 小编也有 5 年编程经验了, 免费送一套比较系统的资料, 教程和工作经验, 就当是福利吧! 21 天速成加 QQ 群: 374890319
- struct Rectangle *r = Rectangle_create(5,5,10,10);
- Shape_area((struct Shape *) r);
"其实吧, 你的兄弟 C++ 的多态实现原理也是类似的! 在运行时查找真正的函数去执行." Ken 总结道.
"对, 这种函数指针的使用方法太常见了, 在我的 Linux 操作系统中也会定义类似的东西." Linus 道.
"只要 IO 设备提供这几个函数的实际定义, 就可以将 File 结构体的函数指针指向对应的实现, 那就实现了用同一套接口操作不同的 IO 设备."
C 语言高兴起来:"哈哈, 我就说我的指针很厉害吧, 这些全是通过指针来实现的."
"是啊, 别听 Java,Python,JavaScript 他们胡说, 你也有对象, 也能进行面向对象的编程!"
C 语言说:"走, 喝酒去!"
来源: http://www.jianshu.com/p/194bc8b57c0e