当前位置: 首页 > 面试题库 >

子子类中协议默认实现的覆盖不参与动态调度。

施宏大
2023-03-14
问题内容

考虑以下游乐场:

protocol A {
    func f() -> String
}

extension A {
    func f() -> String { return "AAAA" }
}

class B: A {}

class C: B {
    func f() -> String { return "CCCC" }
}

let a: A = C()
let b: B = C()
let c: C = C()

a.f() // "AAAA" - why?
b.f() // "AAAA" - why?
c.f() // "CCCC"

我不知道为什么a.f()然后b.f()返回"AAAA"-它们应该返回,"CCCC"因为func f() -> String应该动态调度(如协议中声明的那样)。

如果我更改class B为以下形式:

class B: A {
    func f() -> String { return "BBBB" }
}

然后所有三个呼叫将按预期.f()返回"CCCC"

我觉得这是Swift编译器中的错误,我在Xcode 7.3.1和8.0-beta3中进行了检查,这两种行为都可以重现。

这实际上是预期的行为吗?


问题答案:

您这里涉及到一些规则。

有时使用静态调度(在这种情况下,我们必须查看var / let的类型以找出将要使用的实现)。

其他时间则使用动态分配(这意味着使用变量内部对象的实现)。

让我们考虑一般的例子

let foo: SomeType1 = SomeType2()
foo.f()

我将使用以下定义

  • classic implementation of f() 指示何时在协议扩展之外(因此在struct / class内部)定义了f()。

  • default implementation of f()指示何时f()在协议扩展内定义。

动态调度

如果SomeType1struct/class,则使用自己的“经典”实现,f()然后 应用多态

这意味着如果SomeType2没有经典的实现,f()SomeType1.f()使用。否则SomeType2.f()获胜。

静态调度

如果SomeType1没有的经典实现,f()但具有默认实现,则 关闭多态

在这种情况下,let/var胜出类型的默认实现。

一个。

让我们来看你的第一个例子

let a: A = C()
a.f() // "AAAA"

在此A中没有它自己的经典实现(因为它不是struct / class),但是具有默认实现。因此,多态被关闭并被A.f()使用。

b。

第二个示例的规则相同

let b: B = C()
b.f() // "AAAA"

B没有f()的经典实现,但是默认实现为f()。因此,关闭了多态并使用了B.f()(从协议扩展名开始)。

C。

最后,type的对象位于type Chtml" target="_blank">常量内C

var c:C
c.f() // "CCCC"

C是的经典实现f()。在这种情况下,协议实现将被忽略并C.f()使用。

更多

我们来看另一个例子

protocol Alpha { }
extension Alpha { func f() -> String { return "Alpha"} }
protocol Beta { }
extension Beta { func f() -> String { return "Beta"} }

class Foo: Alpha, Beta { }

let alpha: Alpha = Foo()
alpha.f() // "Alpha"

let beta: Beta = Foo()
beta.f() // "Beta"

如您所见,包含值的常量类型将获胜。如果将Foo对象放入Foo常量中,则会出现编译错误

let foo: Foo = Foo()
foo.f() //

error: ambiguous use of 'f()'
foo.f()
^
Swift 2.playground:2:23: note: found this candidate
extension Beta { func f() -> String { return "Beta"} }
                      ^
Swift 2.playground:6:24: note: found this candidate
extension Alpha { func f() -> String { return "Alpha"} }


 类似资料:
  • 并且,对于不同的目标服务器,目标路径每次都将不同! 清洁/家居对我来说不是一个选择。不幸的是,这里的答案对我来说不是很清楚。

  • 问题内容: 我想知道是否有可能实现这样的目标。 我有一个这样的游乐场: 我可以在中提供默认实现,但是如果需要默认实现中的所有内容以及其他内容,该怎么办? 它在某种程度上类似于es中的调用方法,可以满足实现每个属性等的要求。但是我看不到用实现相同的可能性。 问题答案: 我不知道您是否还在寻找答案,但是要做的方法是从协议定义中删除函数,将对象转换为对象,然后在其上调用方法: 由于某种原因,它仅在函数未

  • 问题内容: Swift协议可以通过向函数和计算属性添加扩展来为其提供默认实现。我已经做了很多次。据我了解, 默认实现仅用作“后备” :当类型符合协议但不提供其自己的实现时,将 执行默认 实现。 至少这就是我阅读《 Swift编程语言》 指南的方式: 如果符合类型提供了自己的所需方法或属性的实现,则将使用该实现而不是扩展提供的实现。 现在,我遇到了这样的情况:我的实现某种协议的自定义类型 确实 为特

  • 这是一个更大的项目,所以我将简化结构,不包括这里涉及的所有代码,但我想知道这在概念上是否可行,以及我可能遇到的潜在障碍。 我从主类中得到了几个级别的子类,其中一个级别包含方法age()(从顶部超类重写),该方法调用useEnergy()。此类的直接子类重写age()。该类的直接子类需要重写useEnergy(),但被重写方法中的代码永远不会执行(通过System.out.printlns验证)。有

  • 问题内容: 我正在尝试使用Swift协议扩展,却发现这种行为令人困惑。您能帮我得到我想要的结果吗? 请参阅代码最后4行的注释。(如果需要,可以将其复制粘贴到Xcode7游乐场)。谢谢!! 问题答案: 简短的答案是协议扩展不执行类多态性。这是有一定道理的,因为协议可以被结构或枚举采用,并且因为我们不希望仅在没有必要的地方采用协议来引入动态调度。 因此,在中,实例变量(可能更准确地写为)并不意味着您认

  • 问题内容: 我遇到了以下代码(Swift 3.1)中解释的问题: 因此,我希望在调用后应打印 _“ SubClassmethodA”_文本。但是由于某种原因,调用了from协议扩展的默认实现。但是,呼叫按预期方式工作。 是协议方法调度中的另一个Swift错误,还是我丢失了一些东西并且代码正常工作? 问题答案: 这就是协议当前调度方法的方式。 协议见证表(有关更多信息,请参见WWDC谈话)用于在协议