前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dart的语法详解系列篇(三)-- mixin入门详解一、继承歧义

Dart的语法详解系列篇(三)-- mixin入门详解一、继承歧义

作者头像
AWeiLoveAndroid
发布2019-01-03 11:11:43
1.6K0
发布2019-01-03 11:11:43
举报

版权声明:本文为博主原创文章,未经博主允许不得转载。https://www.jianshu.com/p/405ba04

在面向对象的编程语言中,Mixin是包含供其他类使用的方法的类,而不必是其他类的父类。其他类如何访问Mixin的方法取决于语言。Mixin有时被描述为“包含的”而不是“继承的”。

Mixins鼓励代码重用,并且可用于避免多重继承可能导致的继承歧义(菱形问题),或者用于解决语言中缺少对多重继承的支持的问题。Mixin还可以被视为具有实现方法的接口。这个模式是执行依赖倒置原则的一个例子。

一、继承歧义

(一)定义

继承歧义,也叫菱形问题,也叫做钻石问题,或者有时被称为致命的死亡钻石。当两个B和C类继承自A,D类继承自B和C时产生歧义。如果A中有一个方法在B和C中已经重写,而D没有重写它,那么D继承的方法的版本是B,还是C?

如下图所示:

钻石问题示意图

(二)继承歧义的缓解

不同的编程语言有不同的方法来处理这些重复继承的问题,这里列举几个用的比较多的语言。

语言

解决方案

C++(底层、硬件、编解码、算法等都用得到)

默认情况下,每个继承路径都是分开的,因此D对象实际上包含两个独立的a对象,并且必须正确限定a成员的使用。如果从A到B的继承和从A到C的继承都标记为virtual(例如,class B:virtual public A),那么c++会特别注意只创建一个对象,并正确使用A的成员。如果虚拟继承和非虚拟继承是混合的,那么只有一个虚拟A,对于每个到A的非虚拟继承路径,都有一个非虚拟A。C++需要显式地声明要使用的特性是从哪个父类调用的(例如:Worker::Human.Age)。C++不支持显式的重复继承,因为没有办法限定要使用哪个超类(例如:在一个派生列表class Dog : public Animal, Animal中出现一个类不止一次)。C++还允许通过虚拟继承机制创建多个类的单个实例(例如:Worker::Human和Musician::Human将引用相同的对象)。

Java8(服务端开发、Android开发)

Java 8在接口上引入默认方法。如果A、B、C是接口,B、C可以为A的抽象方法提供不同的实现,从而导致菱形问题。D类必须重新实现该方法(它的主体可以简单地将调用转发给一个超类来实现),否则模糊将被拒绝作为编译错误。(在Java 8之前,Java不受钻石问题风险的影响,因为它不支持多重继承。)

Go(可以用于区块链有关)

在编译时防止钻石问题。如果一个结构体D嵌入两种结构体B和C(这两个结构体都有一个方法F()),从而满足接口A,那么如果调用D.F(),或者如果D的实例被分配给类型A.B和C的变量,则编译器将会提示ambiguous selector(模拟两可的选择)。

Python(可以用于人工智能有关)

Python的继承顺序影响类语义。Python在引入新样式的类时必须处理这个问题,所有这些类都有一个共同的祖先对象。Python使用C3线性化(或方法解析顺序(Method Resolution Order,MRO))算法创建类列表。该算法强制执行两个约束:子类先于父类,如果一个类从多个类继承,它们将按照基类元组中指定的顺序保存(但是在这种情况下,继承图中较高的一些类可能先于图中较低的类)。因此,方法的分辨率顺序为:D, B, C, A。

Scala(可以用于大数据方面)

Scala允许特性的多个实例化,通过在类层次结构和特征层次结构之间添加区别,可以实现多重继承。类只能从单个类继承,但是可以根据需要混合(mix-in)任意多的特性。Scala使用扩展的traits的右优先深度优先的搜索来解析方法名,然后除去结果列表中每个模块的最后一次出现。所以,解决的顺序是D, C, A, B, A,被减少到D, C, B, A

只允许单个继承(类只能从一个基类派生)的语言没有菱形问题。这样做的原因是,无论方法的重复或位置如何,这些语言在继承链的任何级别上最多只能实现一个方法。通常,这些语言允许类实现多个protocols,在Java中称为接口。这些协议定义了方法,但没有提供具体的实现。这个策略已经被ActionScript、c#、D、Java、Nemerle、Object Pascal (Free Pascal and Delphi)、Objective-C、Smalltalk、Swift、PHP所使用。所有这些语言都允许类实现多个protocols

此外,Ada、Objective-C、c#、Delphi/Free Pascal、Java、Swift、PHP等语言允许接口的多重继承(在Objective-C和Swift中称为protocols(协议))。接口就像抽象基类,它们指定方法签名而不实现任何行为。(“纯”接口,例如版本7之前的Java接口,不允许接口中的任何实现或实例数据。)然而,即使当多个接口声明相同的方法签名时,只要该方法在继承链中的任何位置实现(定义),它就会覆盖该方法在其上链中的任何实现(在它的超类中)。因此,在继承链的任何给定级别上,任何方法最多只能有一个实现。因此,单继承方法实现即使在接口的多继承中也不存在菱形问题。随着Java 8中接口的默认实现的引入,仍然有可能生成菱形问题,尽管这只会作为编译时错误出现。


本文转载自:https://en.wikipedia.org/wiki/Mixin#Programming_languages_that_use_mixins

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.12.30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、继承歧义
    • (一)定义
      • (二)继承歧义的缓解
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档