第十三章 继承
一个类可以继承方法,属性和来自于其他类的特性。当一个类继承另一类的时候,继承的类叫做子类,被继承的类叫做父类,类的继承是一个最基本的行为相比较于swift里面的类和其他类型的不同。
swift里面的类可以调用和读取方法,属性和继承自父类的下标,且可以重写这些方法,属性和下标来优化或修改它 们的行为。Swift 会检查你的重写定义在超类中是否有匹配的定义,以此确保你的重写行为是正确的
可以为类中继承来的属性添加属性观察器,这样一来,当属性值改变时,类就会被通知到。可以为任何属性添加属性观察器,无论它原本被定义为存储型属性还是计算型属性。
1. Defining a Base Class (定义一个基类)
只要是不继承于其他类的任何一个类我们称之为基类。any class that does not inherit from another class is known as a base class。
class Vehicle {
// 默认值为0的存储型属性
var currentSpeed = 0.0
// 计算型属性
var description: String {
return "traveling at \(currentSpeed) miles per hour"
}
// 该类的方法 — 是一种与特定类型(结构体,类或枚举)相关联的函数。
func makeNoise() {
// ... do something later
}
}
/* 类的实例化
用初始化语法创建一个类的实例
即在类名的后面加上一个空白的括号: Vehicle() */
let someVehicle = Vehicle()
print("Vehicle: \(someVehicle.description)")
2. Subclassing (子类)
子类是在已有的类的基础上创建的一个新类,这也已有的类我们称之为父类,创建的新类是子类,子类继承父类里面所有的特性,子类可以进一步完善父类的特性为父类增添新的属性。
下例 是子类如何继承父类和子类,子类在前父类在后中间用:
分开
// 子类Bicycle 父类Vehicle
class Bicycle: Vehicle {
/* 给父类添加一个新的属性
该子类又比父类多了一个hasBasket */
var hasBasket = false
}
// 同样也可以修改继承来自父类的存储属性
bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")
子类同样也可以被其他类进行继承,下面这个例子就是创建了一个自行车的子类。两个座位的自行车叫做Tandem(双人自行车)。
// 其他类(子类的子类)继承子类
class Tandem: Bicycle {
/* 其他类(子类的子类)的一个属性,
这个属性不属于父类(子类),
只是对该类的属性做了补充 */
var currentNumberOfPassengers = 0
}
// 用初始化语法实例化类
let tandem = Tandem()
// 用dot语法对属性做进一步修改
tandem.hasBasket = true
tandem.currentNumberOfPassengers = 2
tandem.currentSpeed = 22.0
print("Tandem: \(tandem.description)")
3. Overriding (重写)
子类可以为实例方法,类型方法,实例属性,类型属性或一个继承父类的下标提供了一个自己的实现。我们称之为重写。所以可以在子类里面对这些类型的属性进行修改或添加。从而达到对这些类型属性的一个重写。
要想重写一个可能会被继承的属性,我们就要在重写定义里用override
关键字介绍并引出将要重写的父类。
override关键字可以要求swift的编译器(complier)来检查要重写的父类是否有定义和存在。父类的定义不正确和没有定义父类那么这时候我们在重写某个父类的时候,编译器就会报错。
3.1 Accessing Superclass Methods, Properties, and Subscripts (读取父类的方法,属性和下标)
当我们为某个子类提供了一个方法,属性或下标的时候,有些时候就会使用已存在的父类的实现作为重写的一部分。这样就可以完善已有父类实现的某个行为,或者存储某个已有继承变量的值。
在合适的情况下,用super前缀来读取父类的某个方法,属性,或下标。
-
一个名为
somethod()
的重写方法可以在重写方法的实现中以调用super.somethod()
的方法来调用父类。(看到super.somethod其实的意思就是这个super.somethod必然在某个子类或子子类的重写实现中会出现,调用super.someM ethod就是来调用某个父类中的someMethod方法)An overridden method named someMethod() can call the superclass version of someMethod() by calling super.someMethod() within the overriding method implementation.
-
一个名为
someProperty
的属性可以在以重写的getter
和setter
的实现里面 可以以super.someProperty
的方式来读取父类中的someProperty
。(super.someProperty也必然是出现在某个子类或子子类的重写中的,用来调用父类中的someProperty的属性。)An overridden property called someProperty can access the superclass version of someProperty as super.someProperty within the overriding getter or setter implementation.
-
为someIndex而重写的一个下标可以在该下标的重写中以
super[someIndex]
的方式来读取父类中相同下标。An overridden subscript for someIndex can access the superclass version of the same subscript as super[someIndex] from within the overriding subscript implementation.
3.2 Overriding Method (重写方法)
我们可以重写一个继承的实例方法或类型方法,从而来为子类的方法提供一个定制或选择性的实现。
下面这个例子,定义了一个新的子类Train,继承于父类Vehicle,新的子类重写了makeNoise()
方法,这个makeNoise() 方法继承于父类Vehicle的属性。
class Train: Vehicle {
// 重写继承于父类的某个方法
override func makeNoise() {
// do something here (refer to super class)
print("Choo Choo")
}
}
// 用初始化语法来实例化这个类
let train = Train()
// dot语法来调用makeNoise()方法 就回输出Choo Choo
train.makeNoise()
3.3 Overriding Property (重写属性)
我们可以重写一个继承的实例属性货类型属性从而为该属性提供一个getter
和setter
,或者添加一个属性观察器(property observers
)来观察重写属性的变化,当潜在的属性值发生变化的时候。
3.3.1 Overriding Property Getter and Setters (重写属性的Getter和Setter)
我们可以用自定义的getter或setter来重写任意一个继承的属性。无论这个继承属性属于计算还是存储属性。(存储和计算型属性都可以用自定义一个getter和setter的方法来重写继承来的属性值)
子类并不知道继承来的属性是存储型的还是计算型的,它只知道继承来的属性会有一个名字和类型。在重写一个属性时,必需将它的名字和类型都写出来。这样才能使编译器去检查你重写的属性是与父类中同名同类型的属性相匹配的。
(子类中的存储或计算型属性的名字和类型要于父类中想要重写的属性值名字和类型要保持一致,这样才能更好地是编译器来检查或重写在子类中父类的属性值)
将一个继承来的只读属性重写为一个读写属性,只需要在重写版本的属性里提供getter
和 setter
。但是不能将一个继承来的读写属性重写为一个只读属性。
下面这个例子定义了一个新的类名为Car
,它是Vehicle
类的一个子类。这个子类有一个新的值为1
的存储属性,和一个要重写父类里面的类型为String
的变量属性。
class Car: Vehicle {
var gear = 1
override var description: String {
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
3.3.2 Overriding Property Observers (重写属性观察器)
我们可以利用属性重写来给继承的属性添加一个属性观察器。这样当一个继承的属性值发生变化的时候。这样我们就会在第一时间获取到属性值变化的通知。
下面这个例子是定义了新的类叫做AutomaticCar
,它是car的一个子类。AutomaticCar代表着是一个自动挡汽车的自动变速器,这个自动变速器基于当前的车速会自动选择一个适当的档位。
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
无论什么时候设置了一个这个新的车速。这个didSet
观察器都会将这个档位属性设置到合适的档位上面去。特别是,属性观察器在选择一个档位的时候是根据这个当前的车速除以10 取整数再加1 得到的就是自动选择的档位值。
3.3 Preventing Overrides (预防重写)
我们可以用final
关键字来预防方法,属性,或者下标的被其他类重写,在方法属性或下标这些介绍关键字前使用final修饰符(final var
,final func
,final class func
,和 final subscript
) 可以更好的预防重写,即表明这些属性方法或下标不可以被重写。
如果在一个子类里带有final
的方法,属性,或下标进行重写,那么就会在代码编译的时候出现错误。可以用final关键字来修饰 添加在类扩展里面的方法属性或下标。
最后,我们同样也可以用final来指明某个完整类的定义(final class
)不可以被重写。在子类里面对父类属性方法或下标的重写,同样会在编译的时候出现错误。