多重继承不好的观点是错误的 — 小评 松本行弘的程序世界

2023-10-05 13:30

本文主要是介绍多重继承不好的观点是错误的 — 小评 松本行弘的程序世界,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

首先得说, 一般某种语言的发明人写的关于自己语言的东西都是非常值得阅读的, 从别的牛人那里你也许能学会很多奇技淫巧, 但从语言发明人那里你能学到语言发明人本身设计的初衷, 以及设计时的一些抉择. 这种思路是独一无二, 绝无仅有的. 所以我在学习一个新语言时, 假如语言发明人有写书, 一定优先阅读.

语言发明人写的书又分两种, 一种是语言的教材, 这个几乎是惯例, 因为一个语言在初期, 没有其他人会用的时候, 语言发明人不教会别人怎么使用, 那可能就没有人会用了, 而他们这本教材的好坏甚至能决定他们语言最后能有多流行. 我听说一个有意思的言论, 说C语言之所以这样流行, 很重要的原因就是C程序设计语言这本教材实在写的太好了. 虽然有些夸张, 但是不无道理, 这个和现在一些开源库对文档要求很高的道理是一样的, 一个开源库的文档写的好不好, 对这个库最后是不是会被很多人使用有极大的关系. 当然, 也有反例, 鬼知道Anders Hejlsberg是怎么把一本C#的语言的教材C#程序设计语言, 写的就像是语言的规格说明书一样.
另外一种, 那就是除了教材外, 写关于自己语言的设计想法的书, 这种书就更加少了, 就目前而言, 我只看到过Bjarne Stroustrup写的C++语言的设计与演化和这本松本行弘的程序世界. 欢迎大家给我推荐其他的类似书籍. C++语言的设计与演化讲述了BS在设计C++时的各种抉择, 看完该书后, 我第一次明白C++到底是怎么设计成那么难用的, 当然, 同时也明白了怎么使用C++是正确的. 后来还反复的读了好几遍, 工作后, 也极力的推荐给使用C++的同事阅读, 事实上, 现在我买的这本书就还在我原来的同事那里, 虽然我已经离开原公司了. 如果说, 那个时候读C++语言的设计与演化还太无知(我那时候才刚刚参加工作), 并且C++又是我接触编程的第一门语言, 导致碰到一些可能习以为常的东西还如获至珍, 所以才这么喜欢的话, 那松本行弘的程序世界在我工作五年, 已经或多或少学习了不下于10门编程语言后, 仍然能给我很多启发, 就更加值得向大家推荐了.

  • Ruby的继承体系
    • Mix-in
      • Ruby的Stream结构
      • C++的Stream结构
  • 本书不足
  • 额外的声明

Ruby的继承体系

多重继承不好的观点是错误的
– 松本行弘

这是我感觉是全书最精彩的部分, 本文也主要关注这一部分. 特别是对于多重继承部分的描述, 充分体现了一个优秀的程序员, 语言设计者的功底.

讲到这里, 我想先讲讲我对这部分内容的认识历史.
在C++语言的设计与演化中, 我们知道, 多重继承在加入C++之前就有争议, 但是BS坚持自己的意见, 最终C++还是支持了多重继承. 并且为被很多人批评的多重继承进行了辩护, 他的确承认了多重继承可能带来的混乱, 但是认为, 在有的时候, 多重继承的抽象的确是有意义的, 并且这种抽象在有的时候会更加优美. 本着C/C++的设计原则, “程序员总是对的”, 不应该人为的去限制程序员, BS坚持的提供了多重继承这一工具, 并让程序员去决定, 什么时候用会导致混乱, 什么时候用可以让设计更加优美.
在成为标准以后, 多重继承的争议一直没有消失, 各种支持多种继承的语言甚至在怎么解决菱形继承上出现了不同的解决方案. 比如C++中, 菱形继承还引入了一个更扭曲的虚继承, Python支持多种继承, 并且因为所有的对象都继承于共同的基类Object, 导致任何多重继承其实都是菱形继承, 当你真的开始自己用多重继承时, 其实继承结构已经是一张网了, 对此, Guido Van Rossum的答案是用深度优先搜索, 靠基类排列的顺序来决定, 个人觉得不仅没有解决这个问题, 反而显的更加神奇.
而无数的JAVA用户者则是把C++的多重继承当作笑话和C++混乱的根源, 自豪的宣布JAVA没有这个问题. James Gosling给出了他自己的解决方案, 那就是没有没有C++自由的多重继承, 只支持对实现的单继承, 并引入了接口, 只允许接口的多重继承. 并且, 在继承接口和继承基类形式上特别加了一些区别, 所以实际中, 很多人并不把这叫做多重继承, 并宣称JAVA没有多重继承.
有意思的是, 高老头后来去了Google, 而我使用C++时尽量遵循的规范Google C++ Style Guide中就明确的规定了禁止C++的多种继承(不代表这两个事情有任何关系), 并且在Style Guide中自己给出了他们的Interface定义, 只允许使用此Interface进行类似JAVA的接口多重继承. 这真是趣事, 在一个Style Guide中, 去强行修改一个语言特性, 也足以证明C++的多重继承有多么臭名昭著了.

就个人感受, 以前开发的一个iOS游戏项目, 仅仅开发了半年, 就因为代码混乱不堪, bug多到无法维护, 项目一度在另外一个工作室被cancel, 然后我们中途再接手开发, 并且把多重继承看作是混乱的根源, 后来整理代码的很大部分工作就是用组件的方式去替代掉混乱的继承, 并且改善后设计清晰了很多, 再后来, 我开发一个Android项目的时候, 第一次真的在项目中去使用JAVA, 深刻的体会到了JAVA对继承的限制, 也真的去实践了GOF在设计模式中早就提到的”组合优于继承”这一设计原则, 也去体会了JAVA社区提倡的面向接口编程. 事实上, 我也逐渐的感觉到了, 其实, “继承本身就是一种强耦合”, 就是一种子类对父类的依赖耦合, 在一些书籍中提到, 甚至继承本身都是不提倡的, 也就是说, 提倡的是基于对象的设计(OB), 而不是面向对象的设计.(OO)

故事到这里就是我的认识了, 鉴于我的认识都来自于各种上述提到的流行语言和经典书籍, 我想大部分人可能会有和我类似的观点吧. 但是Mats不这么看.

Mix-in

本来只是为了跨越继承层次来共享代码, 现在却需要另外生成一个独立对象, 并且每次方法调用都要转送给那个对象, 这实在是不太合理, 而且执行的效率也不高.

Mats直说JAVA对多重继承的解决方式不够方便, 也不太合理. 他提供的解决方案是, Mix-in.
Mix-in按照以下规则来限制多重继承.
通常的继承用单一继承
第二个以及两个以上的父类必须是Mix-in的抽象类

Mix-in类是具有以下特征的抽象类.
不能单独生成实例
不能继承普通类

通过这种在接口和普通多重继承之间的折衷, Mix-in提供了对实现的多重继承, 同时对其进行了限制, 使得继承结构不会成菱形, 而是和单一继承一样的树型. 在Ruby中, Mix-in是通过模块(module)的概念来实现的. 作为例子, Matx用了Ruby中的Stream实现的例子.

Ruby的Stream结构

Ruby

C++的Stream结构

Cpp

从这点看, 为什么我说这是一种折衷方案呢, 因为相对于只允许接口的多重继承来说, 实现更加方便了, 但是, 对于真正的面向对象来说, 毕竟还是需要把一些实现给拆分成更细粒度的类, 才能符合Mix-in的要求. 比如看上面两个图就能发现, 同样的功能, C++需要的类要比Ruby需要的少. 从这点来说, Mats批评JAVA的组合方式为了共享代码需要生成一个独立对象是不方便的, 而实际上Max-in也会相对真正的多重继承来说需要更多的独立对象, 只是使用的方式不是组合, 而是继承. 当然, 这种限制能带来类似JAVA的更加良好的设计, 避免菱形继承及类似更加复杂的继承体系, 同时, 又比JAVA那种方式更加方便, 大家都知道, 加一个继承只要一个单词, 而加一个对象的组合调用, 往往需要增加N个函数接口, 以及N个调用.(虽然有种东西叫做委托) 有趣的事情是, 在编程这件事情上, 很多时候, 折衷的方法却往往是优秀的方法…

本书不足

  1. 作者在前言里面介绍, 是在杂志上连载的文章的基础上编辑修改来的, 所以有些地方其实能发现明显的重复, 甚至不仅仅是文字内容重复, 连Enumerable的那张表都原封不动的重复了两遍.
  2. 后面的章节趣味性有余, 但是感觉思想性稍微有些弱. 所以我看的时候过的比较快, 不过这也见仁见智吧, 也不排除我对相关内容兴趣不足的因素.

额外的声明

我在最新的文章中把所有关于书的链接从豆瓣改为亚马逊了, 假如你点击我的给的链接过去并且买了书, 亚马逊会给我一些佣金, 当然我知道这没有多少, 但是聊胜于无吧, 以后的文章类似, 不再声明了. 我甚至都不知道这样无害的事情为什么需要声明, 但是好像在中国你需要这样做, 因为别人都这么做了.

writen by  九天雁翎(www.jtianling.com)
           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述

这篇关于多重继承不好的观点是错误的 — 小评 松本行弘的程序世界的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/151300

相关文章

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

深度解析Java @Serial 注解及常见错误案例

《深度解析Java@Serial注解及常见错误案例》Java14引入@Serial注解,用于编译时校验序列化成员,替代传统方式解决运行时错误,适用于Serializable类的方法/字段,需注意签... 目录Java @Serial 注解深度解析1. 注解本质2. 核心作用(1) 主要用途(2) 适用位置3

Debian 13升级后网络转发等功能异常怎么办? 并非错误而是管理机制变更

《Debian13升级后网络转发等功能异常怎么办?并非错误而是管理机制变更》很多朋友反馈,更新到Debian13后网络转发等功能异常,这并非BUG而是Debian13Trixie调整... 日前 Debian 13 Trixie 发布后已经有众多网友升级到新版本,只不过升级后发现某些功能存在异常,例如网络转

SpringBoot3匹配Mybatis3的错误与解决方案

《SpringBoot3匹配Mybatis3的错误与解决方案》文章指出SpringBoot3与MyBatis3兼容性问题,因未更新MyBatis-Plus依赖至SpringBoot3专用坐标,导致类冲... 目录SpringBoot3匹配MyBATis3的错误与解决mybatis在SpringBoot3如果

基于Python编写自动化邮件发送程序(进阶版)

《基于Python编写自动化邮件发送程序(进阶版)》在数字化时代,自动化邮件发送功能已成为企业和个人提升工作效率的重要工具,本文将使用Python编写一个简单的自动化邮件发送程序,希望对大家有所帮助... 目录理解SMTP协议基础配置开发环境构建邮件发送函数核心逻辑实现完整发送流程添加附件支持功能实现htm

C#控制台程序同步调用WebApi实现方式

《C#控制台程序同步调用WebApi实现方式》控制台程序作为Job时,需同步调用WebApi以确保获取返回结果后执行后续操作,否则会引发TaskCanceledException异常,同步处理可避免异... 目录同步调用WebApi方法Cls001类里面的写法总结控制台程序一般当作Job使用,有时候需要控制

nginx配置错误日志的实现步骤

《nginx配置错误日志的实现步骤》配置nginx代理过程中,如果出现错误,需要看日志,可以把nginx日志配置出来,以便快速定位日志问题,下面就来介绍一下nginx配置错误日志的实现步骤,感兴趣的可... 目录前言nginx配置错误日志总结前言在配置nginx代理过程中,如果出现错误,需要看日志,可以把

Python错误AttributeError: 'NoneType' object has no attribute问题的彻底解决方法

《Python错误AttributeError:NoneTypeobjecthasnoattribute问题的彻底解决方法》在Python项目开发和调试过程中,经常会碰到这样一个异常信息... 目录问题背景与概述错误解读:AttributeError: 'NoneType' object has no at

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序

使用Docker构建Python Flask程序的详细教程

《使用Docker构建PythonFlask程序的详细教程》在当今的软件开发领域,容器化技术正变得越来越流行,而Docker无疑是其中的佼佼者,本文我们就来聊聊如何使用Docker构建一个简单的Py... 目录引言一、准备工作二、创建 Flask 应用程序三、创建 dockerfile四、构建 Docker