加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Swift4.2语言规范(十五) 继承

发布时间:2020-12-14 05:11:39 所属栏目:百科 来源:网络整理
导读:类可以 从另一个类 继承 方法,属性和其他特性。 当一个类继承自另一个类时,继承类称为 子类 ,它继承的类称为其 超类 。 继承是一种基本行为,它将类与Swift中的其他类型区分开来。 Swift中的类可以调用和访问属于其超类的方法,属性和下标,并可以提供这

类可以从另一个类继承方法,属性和其他特性。当一个类继承自另一个类时,继承类称为子类,它继承的类称为其超类继承是一种基本行为,它将类与Swift中的其他类型区分开来。

Swift中的类可以调用和访问属于其超类的方法,属性和下标,并可以提供这些方法,属性和下标的自己的重写版本,以优化或修改它们的行为。Swift通过检查覆盖定义是否具有匹配的超类定义来帮助确保覆盖是正确的。

类还可以将属性观察器添加到继承的属性,以便在属性值更改时得到通知。属性观察器可以添加到任何属性,无论它最初是被定义为存储属性还是计算属性。

定义基类

任何不从其他类继承的类都称为基类

注意

Swift类不从通用基类继承。您定义的类而不指定超类会自动成为您构建的基类。

下面的示例定义了一个名为的基类Vehicle此基类定义一个名为的存储属性currentSpeed,其默认值为0.0(推断属性类型Double)。currentSpeed属性的值由一个只读的计算String属性使用,该属性被调用description以创建车辆的描述。

所述Vehicle基类还定义了一个称为方法makeNoise此方法实际上并不对基本Vehicle实例执行任何操作,但将由Vehicle以后的子类自定义

1 class Vehicle {
2     var currentSpeed = 0.0
3     var description: String {
4         return "traveling at (currentSpeed) miles per hour"
5     }
6     func makeNoise() {
7         // do nothing - an arbitrary vehicle doesn‘t necessarily make a noise
8     }
9 }

Vehicle使用初始化程序语法创建一个新实例,该语法写为类型名称,后跟空括号:

let someVehicle = Vehicle()

创建新Vehicle实例后,您可以访问其description属性以打印车辆当前速度的可读描述:

1 print("Vehicle: (someVehicle.description)")
2 // Vehicle: traveling at 0.0 miles per hour

Vehicle类定义的共同特点为任意车辆,但没有太大用处本身。为了使其更有用,您需要对其进行优化以描述更具体的车辆类型。

子类

子类化是在现有类上创建新类的行为。子类继承现有类的特征,然后可以对其进行细化。您还可以向子类添加新特征。

要指示子类具有超类,请在超类名称之前写入子类名称,用冒号分隔:

1 class SomeSubclass: SomeSuperclass {
2     // subclass definition goes here
3 }

以下示例定义了一个名为的子类Bicycle,其超类为Vehicle

1 class Bicycle: Vehicle {
2     var hasBasket = false
3 }

新的Bicycle类自动获得所有的特性Vehicle,例如它的currentSpeeddescription特性及其makeNoise()方法。

除了它继承的特性之外,Bicycle该类还定义了一个新的存储属性,hasBasket其默认值为false(推断Bool属性的类型)。

默认情况下,Bicycle您创建的任何新实例都不会有篮子。您可以在创建该实例后为特定实例设置hasBasket属性trueBicycle

1 let bicycle = Bicycle()
2 bicycle.hasBasket = true

您还可以修改继承的currentSpeed一个财产Bicycle实例,查询实例的继承description财产:

1 bicycle.currentSpeed = 15.0
2 print("Bicycle: (bicycle.description)")
3 // Bicycle: traveling at 15.0 miles per hour

子类本身可以是子类。下一个例子Bicycle为双座自行车创建一个子类,称为“串联”:

1 class Tandem: Bicycle {
2     var currentNumberOfPassengers = 0
3 }

Tandem继承了所有属性和方法Bicycle,从而继承了所有的属性和方法VehicleTandem子类还增加了一个新的存储属性调用currentNumberOfPassengers,用的默认值0

如果您创建了一个实例Tandem,则可以使用其任何新的和继承的属性,并查询description它继承的只读属性Vehicle

1 let tandem = Tandem()
2 tandem.hasBasket = true
3 tandem.currentNumberOfPassengers = 2
4 tandem.currentSpeed = 22.0
5 print("Tandem: (tandem.description)")
6 // Tandem: traveling at 22.0 miles per hour

重写

子类可以提供自己的实例方法,类型方法,实例属性,类型属性或下标的自定义实现,否则它将从超类继承。这被称为重写

要覆盖否则将继承的特性,请使用override关键字为覆盖定义添加前缀这样做可以澄清您打算提供覆盖并且没有错误地提供匹配的定义。意外覆盖可能会导致意外行为,并且override在编译代码时,没有关键字的任何覆盖都会被诊断为错误。

override关键字还会提示Swift编译器检查您的重写类的超类(或其父类之一)是否具有与您为重写提供的声明匹配的声明。此检查可确保您的重写定义正确无误。

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

当您为子类提供方法,属性或下标覆盖时,将现有超类实现用作覆盖的一部分有时很有用。例如,您可以优化现有实现的行为,或将修改后的值存储在现有的继承变量中。

如果这是合适的,您可以使用super前缀访问方法,属性或下标的超类版本

  • 名为overridden的方法someMethod()可以someMethod()通过super.someMethod()在重写方法实现中调用来调用超类版本
  • 被称为覆盖的属性someProperty可以访问的超类版本someProperty作为super.someProperty压倒一切的getter或setter实现中。
  • 重写的下标someIndex可以super[someIndex]从重写的下标实现中访问相同下标的超类版本

重写方法

您可以覆盖继承的实例或类型方法,以在子类中提供方法的定制或替代实现。

以下示例定义了一个新的Vehicle被调用子类Train,它覆盖了以下makeNoise()方法Train继承方法Vehicle

1 class Train: Vehicle {
2     override func makeNoise() {
3         print("Choo Choo")
4     }
5 }

如果您创建一个新实例Train并调用其makeNoise()方法,则可以看到该方法的Train子类版本被调用:

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

覆盖属性

您可以覆盖继承的实例或类型属性,以便为该属性提供自己的自定义getter和setter,或添加属性观察器以使覆盖属性能够在基础属性值更改时进行观察。

覆盖属性getter和setter

您可以提供自定义getter(和setter,如果适用)以覆盖任何继承的属性,无论继承的属性是在源上实现为存储属性还是计算属性。子类不知道继承属性的存储或计算性质 - 它只知道继承的属性具有特定的名称和类型。您必须始终声明要覆盖的属性的名称和类型,以使编译器能够检查您的覆盖是否与具有相同名称和类型的超类属性匹配。

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

注意

如果您将setter作为属性覆盖的一部分提供,则还必须为该覆盖提供getter。如果您不想在重写getter中修改继承属性的值,则可以通过super.someProperty从getter?返回来简单地传递继承的值,其中someProperty是您要覆盖的属性的名称。

以下示例定义了一个名为的新类Car,它是一个子类VehicleCar课程介绍了新的存储属性调用gear,用默认整数值1Car类也覆盖了description它从继承属性Vehicle,以提供包括当前齿轮定制描述:

1 class Car: Vehicle {
2     var gear = 1
3     override var description: String {
4         return super.description + " in gear (gear)"
5     }
6 }

description属性的覆盖从调用开始super.description,它返回Vehicle类的description属性。然后,Car该类的版本description在本说明书的末尾添加了一些额外的文本,以提供有关当前档位的信息。

如果你创建的实例Car类,并设置它gearcurrentSpeed属性,你可以看到它的description属性返回中定义的定制描述Car类:

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

覆盖属性观察器

您可以使用属性覆盖将属性观察器添加到继承的属性。这使您可以在继承属性的值更改时收到通知,无论该属性最初如何实现。有关属性观察器的更多信息,请参阅Property Observers

注意

您不能将属性观察器添加到继承的常量存储属性或继承的只读计算属性。无法设置这些属性的值,因此不适合将提供willSetdidSet实现作为覆盖的一部分。

另请注意,您不能同时为同一属性提供重写setter和覆盖属性观察器。如果要观察属性值的更改,并且您已经为该属性提供了自定义setter,则只需观察自定义setter中的任何值更改即可。

以下示例定义了一个名为的新类AutomaticCar,它是一个子类Car所述AutomaticCar类表示用自动变速器,自动选择适当的齿轮使用基于当前速度一辆车:

1 class AutomaticCar: Car {
2     override var currentSpeed: Double {
3         didSet {
4             gear = Int(currentSpeed / 10.0) + 1
5         }
6     }
7 }

当你设置currentSpeed一个的属性AutomaticCar实例属性的didSet观察器设置实例的gear属性齿轮的新速度一个合适的选择。具体来说,属性观察器选择一个新currentSpeed值除以的齿轮,10向下舍入到最接近的整数,加号135.0生产齿轮的速度4

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

防止覆盖

您可以通过将方法,属性或下标标记为final来阻止它被覆盖通过写做到这一点final的方法,属性,或标的介绍人关键字之前修饰符(如,和)。final?varfinal?funcfinal?class?funcfinal?subscript

任何覆盖子类中的最终方法,属性或下标的尝试都会报告为编译时错误。您添加到扩展中的类的方法,属性或下标也可以在扩展的定义中标记为final。

您可以通过在类定义(final?class)中的final?class关键字之前编写修饰符来将整个类标记为final?任何将最终类子类化的尝试都会报告为编译时错误。final?class

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读