为什么以下代码在#2处打印“BaseP”?

protocol BaseP { func foo() }
extension BaseP { func foo() { print("BaseP") } }
protocol SubP: BaseP {}
extension SubP { func foo() { print("SubP") } }

class C: SubP {}
let subP1: SubP = C()
subP1.foo()   //  #1 prints "SubP", fine.

class BaseC: BaseP {}
class SubC: BaseC, SubP {}
let subP2: SubP = SubC()
subP2.foo()   //  #2 prints "BaseP". why?


在这两种情况下,我们在静态类型为foo()的引用上调用SubP
引用具有符合SubP的类的动态类型的对象。
即使是静态调度,我也认为它仍应调用SubP.foo()
为什么在第2个调用基本协议(protocol)实现?
另外,为什么从BaseC继承会有所作为
(如果在class SubC行中,我删除了BaseC或将其替换为BaseP
那么它突然打印出“SubP”)?

最佳答案

调用subP1.foo()subP2.foo()时,就是在foo中调用满足协议(protocol)要求fooBaseP。 (即见证BaseP.foo的方法)。 只能有一个这样的见证人。
另一个重要的事情是foo要求不是在SubP中,而是在BaseP中。 SubP的唯一要求是协调者还必须符合BaseP
对于subP1C直接符合SubP。为了解决SubP的唯一要求,C也必须符合BaseP。现在,编译器需要确定哪种方法可以见证foo。有两种方法可用,但SubP扩展名中的一种隐藏了BaseP扩展名中的一种,因此选择了SubP扩展名中的一种作为见证,因此您看到了SubP打印。
对于subP2,当您使fooBaseC一致时,就已经确定BaseP的见证人。在这里,只有一种选择-foo扩展名中的BaseC。当您稍后将SubCSubP兼容时,剩下的唯一要求是SubC也应符合BaseP。好吧,您说SubC继承自BaseC,所以很好。编译器很高兴,foo扩展名中的BaseP最终成为见证人。

09-03 23:42