Swift:使用协议和子类进行动态调度
Swift: dynamic dispatch with protocol and subclass
请考虑以下Swift5个代码:
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
如果 P.call_foo()
中的 foo()
调用被动态调度到 C1.foo()
,那么为什么 P.call_bar()
中的 bar()
调用没有被动态调度到C2.bar()
?
唯一不同的是foo()
在符合P
的class中直接被覆盖,而bar()
只在子class中被覆盖].为什么会有所不同?
鉴于 bar()
是一项协议要求,难道不应该始终动态调度对它的所有调用吗?
在您的扩展上下文中:
extension P {
func call_foo() { foo() }
func foo() { print("P.foo") }
func call_bar() { bar() }
func bar() { print("P.bar") }
}
C2
不存在,P
是一个协议,方法是静态调度的,虽然bar()
是[=18=的要求],但没有实现通过 C1
符合 P
所以:
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
意思是,如果您只引用 some P
,C1
的子类 C2
的行为与它的超类完全相同:call_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
现在 call_bar()
编译器 知道 它必须使用 C1.bar()
所以使用 some P
引用 C2
:
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 的实现。 (我发现它有点 reassuring 当子类表现得像它们的父类时)。
现在让我们检查原始片段:
let c = C2()
c.call_foo() // C1.foo
c.foo() // C1.foo
c.call_bar() // C2.bar
c.bar() // C2.bar
有效!
请考虑以下Swift5个代码:
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
如果 P.call_foo()
中的 foo()
调用被动态调度到 C1.foo()
,那么为什么 P.call_bar()
中的 bar()
调用没有被动态调度到C2.bar()
?
唯一不同的是foo()
在符合P
的class中直接被覆盖,而bar()
只在子class中被覆盖].为什么会有所不同?
鉴于 bar()
是一项协议要求,难道不应该始终动态调度对它的所有调用吗?
在您的扩展上下文中:
extension P {
func call_foo() { foo() }
func foo() { print("P.foo") }
func call_bar() { bar() }
func bar() { print("P.bar") }
}
C2
不存在,P
是一个协议,方法是静态调度的,虽然bar()
是[=18=的要求],但没有实现通过 C1
符合 P
所以:
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
意思是,如果您只引用 some P
,C1
的子类 C2
的行为与它的超类完全相同:call_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
现在 call_bar()
编译器 知道 它必须使用 C1.bar()
所以使用 some P
引用 C2
:
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 的实现。 (我发现它有点 reassuring 当子类表现得像它们的父类时)。
现在让我们检查原始片段:
let c = C2()
c.call_foo() // C1.foo
c.foo() // C1.foo
c.call_bar() // C2.bar
c.bar() // C2.bar
有效!