继承—Swift学习笔记(十六)

来源:互联网 发布:net编程软件 编辑:程序博客网 时间:2024/04/28 20:14

注:本文为自己学习The Swift Programming Language的笔记,其中的例子为引用原书和其他博文或自己原创的。每个例子都会批注一些实践过程中的经验或思考总结。

1.基础

一个类可以继承另外一个类的方法、属性或者其他特性,继承其他类的类叫做子类(subclass),被继承的类是他的父类/超类(superclass)。在Swift中,继承是类独有的特性。

Swift的子类可以调用和访问超类的方法、属性和下标,也可以根据自己的需要重写(override)这些方法、属性和下标,Swift提供重写检查机制。

子类也可以对继承的属性添加属性观察器,可以在继承属性变化时做出相应,这里的继承属性可以是存储属性或这计算属性。

2.基类定义

基类(base class)指的是并不继承任何类的类,Swift并不提供一个所有类都继承的全局基类(区别于Objective-C的NSObject)。

下面定义一个Vehicle交通工具基类,这个例子将贯穿这一章:

class Vehicle {    var numberOfWheels: Int    var maxPassengers: Int    func description() -> String {        return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers"    }    init() {        numberOfWheels = 0        maxPassengers = 1    }}
基类有两个存储属性numberOfWheels和maxPassengers分别记录轮胎数和最大乘客数,方法description描述这个交通工具,构造函数初始化存储属性的值。

3.子类定义

子类定义时在类名后面用分号引出父类名,子类继承除了父类构造函数以外所有的特性(Objective-C是继承构造函数的),下面定义一个Bicycle子类,它继承Vehicle基类:

class Bicycle: Vehicle {    init() {        super.init()        numberOfWheels = 2    }}
由于不隐式继承超类的构造函数,子类需要实现自己的构造函数。子类中有一个默认属性super,它表示该子类的超类,通过调用超类的构造函数来给子类实例的存储属性赋初始值。我们注意到子类中并没有关于numberOfWheels的定义,但由于继承仍然可以修改它的值。

子类也可以作为超类被其他类继承,比如继承自Bicycle类的Tandem双人自行车类:

class Tandem: Bicycle {    init() {        super.init()        maxPassengers = 2    }}
注意,子类只能在构造函数初始化时修改超类的变量属性,继承自超类的常量属性不能被修改。

4.重写

子类可以通过重写(override)来完成自己关于超类的实例方法、类方法、实例属性以及下标的一个实现,也可以直接继承他们。

显式的在要重写的特性前书写前缀override关键字声明即将进行一个重写,这样避免意外重写所带来的不可预见的错误。没有使用关键字override的重写将报一个编译错误。

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

在重写超类的方法、属性和下标时,使用已有的超类的实现方式作为部分实现代码有时候会很有用。

访问超类的方法和属性用super关键字加上点运算符作为前缀:super.someMethod/super.someProperty,而访问超类的下标使用方括号:super[someIndex]

4.2方法重写

子类可以根据需求重写方法来完成为自己所设定的实现。下面的例子中定义一个继承自Vehicle类的Car类,它声明了自己的一个属性speed并且重写了description方法:

class Car: Vehicle {    var speed: Double = 0.0    init() {        super.init()        maxPassengers = 5        numberOfWheels = 4    }    override func description() -> String {        return super.description() + "; "            + "traveling at \(speed) mph"    }}
子类Car的重写方法沿用超类的该方法实现,在后面加了一些反应速度属性的字符串。创建一个Car实例,那么它调用的是重写方法而不是原方法:

let car = Car()println("Car: \(car.description())")// Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph
4.3属性重写

我们可以重写超类的实例属性或者类属性来添加自己的构造器和赋值器,或者给重写属性添加属性观察器。

(1)重写属性构造器和赋值器

任何继承的属性(存储or计算)都可以在子类中添加本地的构造器和赋值器,子类重写属性并不知道它继承的属性是存储属性还是计算属性,它只知道继承属性的名字和类型。所以在重写属性时一定要给出名字和类型,编译器会检查重写是否匹配。

子类可以把一个只读属性重写为可读可写属性,只需要提供getter和setter;但绝不允许把一个可读可写属性重写为只读属性。

在为继承熟型添加赋值器setter时,必须同时提供取值器getter,即使不想修改继承属性的getter,这时的getter可以直接返回super.someProperty。

下面定义一个SpeedLimitedCar类,继承自Car类。它重写speed存储属性,取值器getter为了保持不变返回super.speed,而赋值器setter将比较新值和40,取其中较小者(限速40mph)赋值给super.speed:

class SpeedLimitedCar: Car {    override var speed: Double  {    get {        return super.speed    }    set {        super.speed = min(newValue, 40.0)    }    }}
注意到赋值器中赋值对象时super.speed而不是self.speed,可以这么理解:重写的speed是一个计算属性,真正的speed值存在super.speed中。如果super.speed是计算属性,那么值也有可能在它关联存储属性中,但是继承让我们屏蔽了这个细节。

let limitedCar = SpeedLimitedCar()limitedCar.speed = 60.0println("SpeedLimitedCar: \(limitedCar.description())")// SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph
输出速度是40.0,是重写的赋值器起的作用。

(2)重写属性观察器

给继承属性添加属性观察器来检测继承属性的改变,而不论它原来是怎么实现的。注意不能给[继承常量存储属性]和[继承只读计算属性]添加属性观察器,因为他们不能被修改,并且不能同时给重写属性添加赋值器set和属性观察器willSet或didSet,因为如果要实现观察直接在set中实现。

下面定义一个继承自Car类的AutomaticCar类,它有一个本地存储属性gear表示档位,初始化为1档:

class AutomaticCar: Car {    var gear = 1    override var speed: Double {    didSet {        gear = Int(speed / 10.0) + 1    }    }    override func description() -> String {        return super.description() + " in gear \(gear)"    }}
为重写speed属性添加didSet属性观察器,在speed被设置后调用didSet的代码,给gear赋相应的档位值。

let automatic = AutomaticCar()automatic.speed = 35.0println("AutomaticCar: \(automatic.description())")// AutomaticCar: 4 wheels; up to 5 passengers; traveling at 35.0 mph in gear 4
gear由于speed更改而发生更改。

5.禁止重写

在某些情况下我们不想要类成员如属性、方法和下标等被其他类继承时或者整个类都不想被继承时,可以在这些类成员或类的前面添加@final前缀表示不能继承。继承final类会引发一个编译错误,而final属性等可以被调用但不能重写。


0 0
原创粉丝点击