首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >未调用的子类中的方法自定义

未调用的子类中的方法自定义
EN

Stack Overflow用户
提问于 2015-11-13 22:22:46
回答 1查看 172关注 0票数 1

在协议扩展中默认实现的协议中定义为自定义点的函数似乎不能在子类中自定义,如果基类最初没有自定义该函数,则该子类将通过基类间接继承该协议。

下面是一个简单的协议:

代码语言:javascript
复制
protocol MyProtocol
{
    func myFunc() -> String
}

使用默认实现:

代码语言:javascript
复制
extension MyProtocol
{
    func myFunc() -> String
    {
        return "hello from extension"
    }
}

让我们创建一个基类和一个像这样的子类:

代码语言:javascript
复制
class BaseClass: MyProtocol
{
}

class SubClass: BaseClass
{
    func myFunc() -> String
    {
        return "hello from SubClass"
    }
}

BaseClass().myFunc()                    // "hello from extension"
(BaseClass() as MyProtocol).myFunc()    // "hello from extension"

SubClass().myFunc()                     // "hello from SubClass"
(SubClass() as BaseClass).myFunc()      // "hello from extension"
(SubClass() as MyProtocol).myFunc()     // "hello from extension"

现在使用基类中的自定义:

代码语言:javascript
复制
class BaseClass: MyProtocol
{
    func myFunc() -> String
    {
        return "hello from BaseClass"
    }
}

class SubClass: BaseClass
{
    override func myFunc() -> String
    {
        return "hello from SubClass"
    }
}

BaseClass().myFunc()                    // "hello from BaseClass"
(BaseClass() as MyProtocol).myFunc()    // "hello from BaseClass"

SubClass().myFunc()                     // "hello from SubClass"
(SubClass() as BaseClass).myFunc()      // "hello from SubClass"
(SubClass() as MyProtocol).myFunc()     // "hello from SubClass"

这是一种预期的行为吗?

编辑14-11月:

关于本文的说明:http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future来自matt注释:

我认为这与我的问题没有严格的关系,因为这篇文章没有涉及子类间接继承协议的情况(这似乎会产生影响)。在后一种情况下,即使函数是定制点(协议需求的一部分),静态分派也不明显。根据调用时推断的类型,行为不同。

本文还介绍了另一种情况,即函数在扩展中具有默认实现,而不是协议需求的一部分,并且可能隐藏子类自定义。

编辑11月17日:

可能是In Swift, why subclass method cannot override the one, provided by protocol extension in superclass的副本

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-11-14 17:16:19

带有方法实现的协议扩展会使我们陷入这样一种情况:有时我们是多态的(对象的内部类型才是最重要的),而有时则不是(对象的外部类型或转换方式才是最重要的)。

为了探索这一点,我使用了一个测试网格,涵盖以下参数:

  • 协议本身也需要这个方法吗?
  • 采用者是结构还是类?
  • 采用者是否实施该方法?

1.议定书不要求采用这种方法。

我们首先回答第一个问题是否定的。下面是类型声明:

代码语言:javascript
复制
protocol Flier {
}
extension Flier {
    func fly() {
        print("flap flap flap")
    }
}
struct Bird : Flier {
}
struct Insect : Flier {
    func fly() {
        print("whirr")
    }
}
class Rocket : Flier {
    func fly() {
        print("zoooom")
    }
}
class AtlasRocket : Rocket {
    override func fly() {
        print("ZOOOOOM")
    }
}
class Daedalus : Flier {
    // nothing
}
class Icarus : Daedalus {
    func fly() {
        print("fall into the sea")
    }
}

以下是测试结果:

代码语言:javascript
复制
let b = Bird()
b.fly() // flap flap flap
(b as Flier).fly() // flap flap flap

let i = Insect()
i.fly() // whirr
(i as Flier).fly() // flap flap flap

let r = Rocket()
r.fly() // zoooom
(r as Flier).fly() // flap flap flap

let r2 = AtlasRocket()
r2.fly() // ZOOOOOM
(r2 as Rocket).fly() // ZOOOOOM
(r2 as Flier).fly() // flap flap flap

let d = Daedalus()
d.fly() // flap flap flap
(d as Flier).fly() // flap flap flap

let d2 = Icarus()
d2.fly() // fall into the sea
(d2 as Daedalus).fly() // flap flap flap
(d2 as Flier).fly() // flap flap flap

结果:如何输入对象是很重要的。实际上,编译器只知道对象的输入方式,在哪里查找将被调用的fly实现;编译时提供了所有必要的信息。一般来说,不需要动态调度。

例外是AtlasRocket,它是一个子类,它的超类有自己的实现。当AtlasRocket被键入为它的超类火箭时,它仍然是(为了飞行目的)一个AtlasRocket。但这并不令人惊讶,因为这是子类/超类的情况,多态和动态分派是有效的;显然,我们不会仅仅因为故事中还有协议扩展而关闭动态调度。

2.议定书确实要求采用这种方法

现在,第一个问题的答案是肯定的。类型声明与以前完全相同,只不过我在所有类型的名称中添加了一个"2“,并且协议本身包含了该方法,这是必需的:

代码语言:javascript
复制
protocol Flier2 {
    func fly() // *
}
extension Flier2 {
    func fly() {
        print("flap flap flap")
    }
}
struct Bird2 : Flier2 {
}
struct Insect2 : Flier2 {
    func fly() {
        print("whirr")
    }
}
class Rocket2 : Flier2 {
    func fly() {
        print("zoooom")
    }
}
class AtlasRocket2 : Rocket2 {
    override func fly() {
        print("ZOOOOOM")
    }
}
class Daedalus2 : Flier2 {
    // nothing
}
class Icarus2 : Daedalus2 {
    func fly() {
        print("fall into the sea")
    }
}

下面是测试;它们是相同的测试,所有类型的名称中都添加了"2“:

代码语言:javascript
复制
let b = Bird2()
b.fly() // flap flap flap

let i = Insect2()
i.fly() // whirr
(i as Flier2).fly() // whirr (!!!)

let r = Rocket2()
r.fly() // zoooom
(r as Flier2).fly() // zoooom (!!!)

let r2 = AtlasRocket2()
r2.fly() // ZOOOOOM
(r2 as Rocket2).fly() // ZOOOOOM
(r2 as Flier2).fly() // ZOOOOOM (!!!)

let d = Daedalus2()
d.fly() // flap flap flap
(d as Flier2).fly() // flap flap flap

let d2 = Icarus2()
d2.fly() // fall into the sea
(d2 as Daedalus2).fly() // flap flap flap
(d2 as Flier2).fly() // flap flap flap

结果:多态性已经出现在生活中:一个物体到底是什么,重要的是什么。你可以称Insect2为Flier2,但它仍然像Insect2一样飞行。你可以称Rocket2为Flier2,但它仍然像Rocket2一样飞行。你可以称AtlasRocket2为Flier2,但它仍然像AtlasRocket2一样飞行。

这里的例外情况是您的问题所指出的情况,即当采用者本身没有实现该方法时。因此,我们将Icarus2称为Daedalus2,瞧,它像Daedalus2一样飞行,与前面的例子完全一样。不需要打开多态,编译器从一开始就知道这一点,因为Icarus2 2的实现不是override

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33702738

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档