Swift继承

目录

引入

一个类可以从另一个类继承方法、 属性和其他特性。 当一个类从另一个类继承时, 继承的类被称为子类, 它所继承的类被称为超类。 继承是Swift中类区别于其他类型的基本行为。

Swift中的类可以调用和访问属于其超类的方法、 属性和下标, 还可以提供自己的方法、 属性和下标重载版本, 以完善或修改其行为。 Swift会检查覆盖定义是否有匹配的超类定义, 以确保覆盖正确无误。

类还可以为继承属性添加属性观察者, 以便在属性值发生变化时收到通知。

定义基类

不继承自其他类的类都称为基类。

class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }
    func makeNoise() {
        // do nothing - an arbitrary vehicle doesn't necessarily make a noise
    }
}

let someVehicle = Vehicle()
print("Vehicle: \(someVehicle.description)") // Vehicle: traveling at 0.0 miles per hour

子类

子类是在现有类的基础上创建新类的行为。

子类继承现有类的特征, 然后可以对其进行完善。 您还可以为子类添加新的特性。

要表示一个子类有一个超类, 请将子类名称写在超类名称之前, 中间用冒号隔开。

class SomeSubclass: SomeSuperclass {
    // 子类定义
}

示例

class Bicycle: Vehicle {
    var hasBasket = false
}

let bicycle = Bicycle()
bicycle.hasBasket = true

// 查询和修改继承的属性
bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")

子类也可以子类化。

class Tandem: Bicycle {
    var currentNumberOfPassengers = 0
}

let tandem = Tandem()
tandem.hasBasket = true
tandem.currentNumberOfPassengers = 2
tandem.currentSpeed = 22.0
print("Tandem: \(tandem.description)")
// Tandem: traveling at 22.0 miles per hour

重写

子类可以为其从超类继承的实例方法、 类型方法、 实例属性、 类型属性或下标提供自己的自定义实现。 这就是所谓的重写。

要重写一个本应继承的特性, 必须在重写定义前加上 override 关键字。 这样做说明你打算提供一个重写, 而不是错误地提供了一个匹配的定义。 意外重写可能会导致意外的行为, 在编译代码时, 任何没有关键字的重写都会被认为错误。

重写关键字还会提示编译器检查重写类的超类(或其父类之一)是否有与您为重写提供的声明相匹配的声明。

访问超类方法、属性和下标

当你为子类提供方法、 属性或下标重写时, 使用现有的超类实现作为重写的一部分有时会很有用。 例如,你可以改进现有实现的行为,或在现有继承变量中存储修改后的值。

在适当的情况下,可以使用 super 前缀访问超类版本的方法、 属性或下标。

重写方法

你可以重写继承的实例或类型方法, 以便在子类中提供该方法的定制或替代实现。

class Train: Vehicle {
    override func makeNoise() {
        print("Choo Choo")
    }
}

let train = Train()
train.makeNoise()
// Prints "Choo Choo"

重写属性

你可以重写继承的实例或类型属性, 为该属性提供自己的自定义获取器和设置器, 或添加属性观察器,使重写属性能在底层属性值发生变化时观察到变化。

重写属性getter和setter

你可以提供一个自定义获取器(和设置器,如果合适)来重写任何继承属性, 无论该继承属性在源代码中是作为存储属性还是计算属性实现的。 子类并不知道继承属性的存储或计算性质, 它只知道继承属性具有特定的名称和类型。 你必须始终说明你要重写的属性的名称和类型, 以便编译器检查你的重写是否与具有相同名称和类型的超类属性相匹配。

通过在子类属性重写中提供 getter 和 setter, 可以将继承的只读属性显示为读写属性。 但不能将继承的可读写属性作为只读属性。

class Car: Vehicle {
    var gear = 1
    // 重写description属性
    override var description: String {
        // 通过super.属性名访问超类属性
        return super.description + " in gear \(gear)"
    }
}

let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print("Car: \(car.description)")
// Car: traveling at 25.0 miles per hour in gear 3

重写属性观察器

你可以使用属性重载为继承属性添加属性观察器。 当继承属性的值发生变化时, 无论该属性最初是如何实现的, 你都能收到通知。

class AutomaticCar: Car {
    override var currentSpeed: Double {
        didSet {
            gear = Int(currentSpeed / 10.0) + 1
        }
    }
}

let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
// AutomaticCar: traveling at 35.0 miles per hour in gear 4

防止重写

通过将方法、 属性或下标标记为 final,可以防止其被重写。

具体做法是在方法、 属性或下标引入关键字(如 final var、final func、final class func 和 final subscript)前写入 final 修饰符。

任何在子类中重载 final 方法、 属性或下标的尝试都会在编译时报错。

在类定义中的类关键字前写入 final 修饰符(final class),可以将整个类标记为 final。 任何对 final 类进行子类化的尝试都会在编译时报错。

class Car {
    var brand: String
    
    init(brand: String) {
        self.brand = brand
    }
    
    final func showBrand() {
        print(self.brand)
    }
}

class Truck: Car {
    var capacity: Double
    
    init(capacity: Double, brand: String) {
        self.capacity = capacity
        super.init(brand: brand)
    }
    
    override func showBrand() { // Instance method overrides a 'final' instance method
        print("hehe")
    }
}