Swift:带有协议和子类的动态调度

2024-01-23

请考虑以下 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

If the foo()打电话进来P.call_foo()被动态分派到C1.foo(),那么为什么bar()打电话进来P.call_bar()不会被动态分派到C2.bar()?

唯一的区别是foo()在符合的类中直接被覆盖P, and 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,它不是由C1其符合P so:

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,子类C2 of C1其行为与它的超类完全相同:call_bar() calls P.bar()因为C1不实施bar()

现在让我们看看如果你实施会发生什么bar() in C1:

class C1: P {
    func foo() { print("C1.foo") }
    func bar() { print("C1.bar") }
}

class C2: C1 {
    override func bar() { print("C2.bar") }
}

如果我们使用引用C1 using some P:

let c1: some P = C1()
c1.call_foo()    //  C1.foo
c1.foo()         //  C1.foo
c1.call_bar()    //  C1.bar
c1.bar()         //  C1.bar

now in call_bar()编译器knows它必须使用C1.bar()所以参考C2 using some P:

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()被叫了。 (而且我觉得有点令人安心的 https://en.wikipedia.org/wiki/Liskov_substitution_principle当子类表现得像它们的父类时)。

现在让我们检查原始片段:

let c = C2()
c.call_foo()    //  C1.foo
c.foo()         //  C1.foo
c.call_bar()    //  C2.bar
c.bar()         //  C2.bar

有用 !

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Swift:带有协议和子类的动态调度 的相关文章

随机推荐