为什么不允许子类使用派生类型覆盖超类属性?

时间:2018-08-25 15:10:58

标签: swift oop subclassing

Swift编程语言允许子类重写具有相同类型T的超类属性,但不能替代具有不同类型S的超类属性,即使S衍生自T也不例外。这是https://docs.swift.org/swift-book/LanguageGuide/Inheritance.html的引号:

  

您必须始终声明您的属性的名称和类型   覆盖,使编译器能够检查您的覆盖   匹配具有相同名称和类型的超类属性。

在重写方法时,Swift确实允许重写的子类方法返回从超类方法的返回类型派生的类型。

我的问题是:禁止子类覆盖具有从T派生的类型S的超类属性的动机是什么?

1 个答案:

答案 0 :(得分:1)

这实际上并不限于Swift。这将破坏多态性。请参见wikipedia: Subtyping

上的子类型化规则

基本上,请考虑以下示例:

class A {
   var x: NSObject?
}

class B: A {
   override var x: NSNumber?
}

并考虑:

let b = B(x: 1)
let a: A = b // it's a subclass, polymorphism allows to assign it to A
a.x = NSObject() // let's assign NSObject() because A.x takes NSObject
print(b.x) // b.x should be a NSNumber now but we have assigned a NSObject?

您必须认识到,属性是两个函数的组合,即setter和getter。您可以在getter(函数的返回值)中添加更特定的类型(协变类型),但不能对setter进行此操作(重写函数的参数需要互变)。

这还告诉您这将与readonly属性一起工作:

class A {
    var x: NSObject? {
        return NSObject()
    }
}

class B: A {
    override var x: NSNumber? {
        return NSNumber()
    }
}