Swift:具有协议和子类的动态调度 请考虑以下SWIFT 5代码: protocol P: class { func call_foo() func foo() func call_bar() func bar() } extension P { func call_foo() { foo() } func foo() { print("P.foo") } func call_bar() { bar() } func bar() { print("P.bar") } } class C1: P { func foo() { print("C1.foo") } } class C2: C1 { func bar() { print("C2.bar") } } let c = C2() c.call_foo() // C1.foo c.foo() // C1.foo c.call_bar() // P.bar c.bar() // C2.bar
如果Swift:具有协议和子类的动态调度 请考虑以下SWIFT 5代码: protocol P: class { func call_foo() func foo() func call_bar() func bar() } extension P { func call_foo() { foo() } func foo() { print("P.foo") } func call_bar() { bar() } func bar() { print("P.bar") } } class C1: P { func foo() { print("C1.foo") } } class C2: C1 { func bar() { print("C2.bar") } } let c = C2() c.call_foo() // C1.foo c.foo() // C1.foo c.call_bar() // P.bar c.bar() // C2.bar,swift,protocols,dynamic-dispatch,Swift,Protocols,Dynamic Dispatch,如果foo()调用p.call\u foo()被动态调度到C1.foo(),那么为什么bar()调用p.call\u bar()没有被动态调度到C2.bar() 唯一的区别是foo()在符合p的类中被直接重写,bar()仅在子类中被重写。为什么会有不同 鉴于bar()是协议要求,对它的所有调用不应该总是动态调度吗?在您的扩展上下文中: extension P { func call_foo() { foo() } func foo() { print("P.foo&qu
foo()
调用p.call\u foo()
被动态调度到C1.foo()
,那么为什么bar()
调用p.call\u bar()
没有被动态调度到C2.bar()
唯一的区别是foo()
在符合p
的类中被直接重写,bar()
仅在子类中被重写。为什么会有不同
鉴于
bar()
是协议要求,对它的所有调用不应该总是动态调度吗?在您的扩展上下文中:
extension P {
func call_foo() { foo() }
func foo() { print("P.foo") }
func call_bar() { bar() }
func bar() { print("P.bar") }
}
C2
不存在,p
是一个协议,方法是静态调度的,虽然bar()
是p
的一个要求,但它不是由符合p
的C1
实现的,因此:
let c1: some P = C1()
c1.call_foo() // C1.foo
c1.foo() // C1.foo
c1.call_bar() // P.bar
c1.bar() // P.bar
这很正常,有趣的是你有:
let someP: some P = C2()
someP.call_foo() // C1.foo
someP.foo() // C1.foo
someP.call_bar() // P.bar
someP.bar() // P.bar
这意味着,如果您只引用了某些p
,则C1
的子类C2
的行为与它的超类完全相同:call\u bar()
调用p.bar()
,因为C1
没有实现bar()
现在让我们看看如果在C1
中实现bar()
会发生什么:
class C1: P {
func foo() { print("C1.foo") }
func bar() { print("C1.bar") }
}
class C2: C1 {
override func bar() { print("C2.bar") }
}
如果我们使用some p
引用C1
:
let c1: some P = C1()
c1.call_foo() // C1.foo
c1.foo() // C1.foo
c1.call_bar() // C1.bar
c1.bar() // C1.bar
let someP: some P = C2()
someP.call_foo() // C1.foo
someP.foo() // C1.foo
someP.call_bar() // C2.bar
someP.bar() // C2.bar
现在在call\u bar()
中,编译器知道它必须使用C1.bar()
,因此对于C2
的引用,使用一些p
:
let c1: some P = C1()
c1.call_foo() // C1.foo
c1.foo() // C1.foo
c1.call_bar() // C1.bar
c1.bar() // C1.bar
let someP: some P = C2()
someP.call_foo() // C1.foo
someP.foo() // C1.foo
someP.call_bar() // C2.bar
someP.bar() // C2.bar
子类C2
的行为仍然与它的超类C1
相同,并且它的bar()
get的实现被调用。(当子类的行为与它们的父类相同时,我会发现这一点)
现在让我们检查原始代码段:
let c = C2()
c.call_foo() // C1.foo
c.foo() // C1.foo
c.call_bar() // C2.bar
c.bar() // C2.bar
它的工作 我是否正确理解,
C1
与p的一致性只有一个见证表(与之相反,C1
的每个子类都有一个单独的见证表),在C1
的所有实例或其任何子类之间共享?是的,有关更多详细信息,请参见@Hamish answer here:好的,谢谢。这解释了我所看到的行为,尽管我仍然不理解背后的原理。谢谢你的链接,我会继续阅读。