Swift 中使用不同类型覆盖超类属性
我们可以在 Swift 语言中定义一个从超类继承的子类,这意味着可以使用 override 关键字覆盖其属性和方法。
但是,不能在子类中使用不同类型覆盖属性。默认情况下,子类必须覆盖与超类类型相同的类型的属性。
例如,假设您有一个 Person 类,其中 name 和 age 属性的类型分别为 String 和 Double:
class Person { let name: String let age: Double init(name: String, age: Double) { self.name = name self.age = age } }
现在,假设您有一个名为 Student 的子类从 Person 继承,并且您想将 age 属性覆盖为 Int 类型:
class Student: Person { let grade: Int override var age: Int { return age } }
此代码将产生编译时错误,因为 Student 子类中 age 属性的类型与 Person 超类中 age 属性的类型不同。错误如下所示:
error: property 'age' with type 'Int' cannot override a property with type 'Double'
以下是一些在 Swift 中使用不同类型覆盖超类属性的示例:
示例 1:使用子类型覆盖超类属性
步骤 1 − 在此示例中,Dog 类使用相同的类型(String)覆盖了 Animal 类的 name 属性。
步骤 2 − 但是,它还添加了一个 didSet 观察器,每当设置 name 属性时打印“Dark!”。
步骤 3 − 这是一个关于如何在保持相同类型的同时向继承属性添加功能的示例。
import Foundation class Animal { var name: String init(name: String) { self.name = name } } class Dog: Animal { override var name: String { didSet { print("Bark!") } } } let dog = Dog(name: "Tommy") dog.name = "Harry"
输出
Bark!
示例 2:使用计算属性覆盖超类属性
import Foundation class Shape { var area: Double { fatalError("Subclasses must override this property") } } class Rectangle: Shape { var width: Double var height: Double init(width: Double, height: Double) { self.width = width self.height = height } override var area: Double { return width * height } } let rectangle = Rectangle(width: 10.0, height: 20.0) print(rectangle.area)
输出
200.0
在此示例中,Shape 类定义了一个名为 area 的只读属性,如果它没有被子类覆盖,则会导致致命错误。Rectangle 类用一个计算属性替换了矩形的 area 属性,该属性使用 width 和 height 值计算矩形的面积。这是一个说明如何使用计算属性在每个子类中定义行为不同的继承属性的示例。
示例 3:在子类中使用额外变量覆盖超类属性
import Foundation class Person { let name: String let age: Double init(name: String, age: Double) { self.name = name self.age = age } } class Student: Person { var grade: Int init(grade: Int) { self.grade = grade super.init(name: "", age: 0.0) } } class School { var person = Person(name: "", age: 0.0) } class PrimarySchool: School { var student = Student(grade: 8) override var person: Person { get { return student } set { if let newStudent = newValue as? Student { student = newStudent } else { print("Incorrect student type for primary school.") } } } }
似乎不能使用 let 语法声明一个属性并在其子类中用 var 覆盖它,反之亦然,这可能是因为超类实现可能不希望该属性在初始化后发生更改。
因此,在这种情况下,也需要在超类中使用 'var' 声明属性以匹配子类(如上所示)。如果不能更改超类中的源代码,那么最好在每次需要修改人员时都销毁当前的 RaceCar 并创建一个新的 PrimarySchool。
结论
Swift 提供了在子类中覆盖属性和方法的灵活性。此外,您可以在子类中使用不同类型覆盖超类的属性。
为此,如果要更改超类属性的实际类型,可以使用计算属性而不是存储属性。使用计算属性,您可以使用不同的类型覆盖 getter 和 setter。