fix 2.13 inheritance

This commit is contained in:
stanzhai
2014-06-14 17:55:09 +08:00
parent 4de16a1d89
commit e13d4f3cb7

View File

@ -1,6 +1,5 @@
> 翻译Hawstein > 翻译Hawstein
> 校对menlongsheng
> 校对menlongsheng
# 继承Inheritance # 继承Inheritance
------------------- -------------------
@ -23,13 +22,12 @@
不继承于其它类的类,称之为*基类base calss*。 不继承于其它类的类,称之为*基类base calss*。
> 注意: > 注意:
>
Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。 Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。
下面的例子定义了一个叫`Vehicle`的基类。这个基类声明了两个对所有车辆都通用的属性(`numberOfWheels``maxPassengers`)。这些属性在`description`方法中使用,这个方法返回一个`String`类型的,对车辆特征的描述: 下面的例子定义了一个叫`Vehicle`的基类。这个基类声明了两个对所有车辆都通用的属性(`numberOfWheels``maxPassengers`)。这些属性在`description`方法中使用,这个方法返回一个`String`类型的,对车辆特征的描述:
``` ```swift
class Vehicle { class Vehicle {
var numberOfWheels: Int var numberOfWheels: Int
var maxPassengers: Int var maxPassengers: Int
@ -49,7 +47,7 @@ class Vehicle {
构造器的最简单形式就像一个没有参数的实例方法,使用`init`关键字: 构造器的最简单形式就像一个没有参数的实例方法,使用`init`关键字:
``` ```swift
init() { init() {
// 执行构造过程 // 执行构造过程
} }
@ -57,7 +55,7 @@ init() {
如果要创建一个`Vehicle`类的新实例,使用*构造器*语法调用上面的初始化器,即类名后面跟一个空的小括号: 如果要创建一个`Vehicle`类的新实例,使用*构造器*语法调用上面的初始化器,即类名后面跟一个空的小括号:
``` ```swift
let someVehicle = Vehicle() let someVehicle = Vehicle()
``` ```
@ -72,18 +70,19 @@ let someVehicle = Vehicle()
为了指明某个类的超类,将超类名写在子类名的后面,用冒号分隔: 为了指明某个类的超类,将超类名写在子类名的后面,用冒号分隔:
``` ```swift
class SomeClass: SomeSuperclass { class SomeClass: SomeSuperclass {
// 类的定义 // 类的定义
} }
``` ```
下一个例子,定义一个更具体的车辆类叫`Bicycle`。这个新类是在 `Vehicle`类的基础上创建起来。因此你需要将`Vehicle`类放在 `Bicycle`类后面,用冒号分隔。 下一个例子,定义一个更具体的车辆类叫`Bicycle`。这个新类是在 `Vehicle`类的基础上创建起来。因此你需要将`Vehicle`类放在 `Bicycle`类后面,用冒号分隔。
我们可以将这读作: 我们可以将这读作:
“定义一个新的类叫`Bicycle `,它继承了`Vehicle`的特性”; “定义一个新的类叫`Bicycle `,它继承了`Vehicle`的特性”;
``` ```swift
class Bicycle: Vehicle { class Bicycle: Vehicle {
init() { init() {
super.init() super.init()
@ -91,19 +90,19 @@ class Bicycle: Vehicle {
} }
} }
``` ```
`Bicycle``Vehicle`的子类,`Vehicle``Bicycle`的超类。新的`Bicycle`类自动获得`Vehicle`类的特性,比如 `maxPassengers``numberOfWheels`属性。你可以在子类中定制这些特性,或添加新的特性来更好地描述`Bicycle`类。 `Bicycle``Vehicle`的子类,`Vehicle``Bicycle`的超类。新的`Bicycle`类自动获得`Vehicle`类的特性,比如 `maxPassengers``numberOfWheels`属性。你可以在子类中定制这些特性,或添加新的特性来更好地描述`Bicycle`类。
`Bicycle`类定义了一个构造器来设置它定制的特性自行车只有2个轮子`Bicycle`的构造器调用了它父类`Vehicle`的构造器 `super.init()`,以此确保在`Bicycle`类试图修改那些继承来的属性前`Vehicle`类已经初始化过它们了。 `Bicycle`类定义了一个构造器来设置它定制的特性自行车只有2个轮子`Bicycle`的构造器调用了它父类`Vehicle`的构造器 `super.init()`,以此确保在`Bicycle`类试图修改那些继承来的属性前`Vehicle`类已经初始化过它们了。
> 注意: > 注意:
>
不像 Objective-C在 Swift 中,初始化器默认是不继承的,见[初始化器的继承与重写](../chapter2/_14Initialization.html#initializer_inheritance_and_ overriding) 不像 Objective-C在 Swift 中,初始化器默认是不继承的,见[初始化器的继承与重写](../chapter2/_14Initialization.html#initializer_inheritance_and_ overriding)
`Vehicle`类中`maxPassengers`的默认值对自行车来说已经是正确的,因此在`Bicycle`的构造器中并没有改变它。而`numberOfWheels`原来的值对自行车来说是不正确的,因此在初始化器中将它更改为 2。 `Vehicle`类中`maxPassengers`的默认值对自行车来说已经是正确的,因此在`Bicycle`的构造器中并没有改变它。而`numberOfWheels`原来的值对自行车来说是不正确的,因此在初始化器中将它更改为 2。
`Bicycle`不仅可以继承`Vehicle`的属性,还可以继承它的方法。如果你创建了一个`Bicycle`类的实例,你就可以调用它继承来的`description`方法,并且可以看到,它输出的属性值已经发生了变化: `Bicycle`不仅可以继承`Vehicle`的属性,还可以继承它的方法。如果你创建了一个`Bicycle`类的实例,你就可以调用它继承来的`description`方法,并且可以看到,它输出的属性值已经发生了变化:
``` ```swift
let bicycle = Bicycle() let bicycle = Bicycle()
println("Bicycle: \(bicycle.description())") println("Bicycle: \(bicycle.description())")
// Bicycle: 2 wheels; up to 1 passengers // Bicycle: 2 wheels; up to 1 passengers
@ -111,7 +110,7 @@ println("Bicycle: \(bicycle.description())")
子类还可以继续被其它类继承: 子类还可以继续被其它类继承:
``` ```swift
class Tandem: Bicycle { class Tandem: Bicycle {
init() { init() {
super.init() super.init()
@ -122,13 +121,12 @@ class Tandem: Bicycle {
上面的例子创建了`Bicycle`的一个子类双人自行车tandem`Tandem``Bicycle`继承了两个属性,而这两个属性是`Bicycle``Vehicle`继承而来的。`Tandem`并不修改轮子的数量,因为它仍是一辆自行车,有 2 个轮子。但它需要修改`maxPassengers`的值,因为双人自行车可以坐两个人。 上面的例子创建了`Bicycle`的一个子类双人自行车tandem`Tandem``Bicycle`继承了两个属性,而这两个属性是`Bicycle``Vehicle`继承而来的。`Tandem`并不修改轮子的数量,因为它仍是一辆自行车,有 2 个轮子。但它需要修改`maxPassengers`的值,因为双人自行车可以坐两个人。
> 注意: > 注意:
>
子类只允许修改从超类继承来的变量属性,而不能修改继承来的常量属性。 子类只允许修改从超类继承来的变量属性,而不能修改继承来的常量属性。
创建一个`Tandem`类的实例,打印它的描述,即可看到它的属性已被更新: 创建一个`Tandem`类的实例,打印它的描述,即可看到它的属性已被更新:
``` ```swift
let tandem = Tandem() let tandem = Tandem()
println("Tandem: \(tandem.description())") println("Tandem: \(tandem.description())")
// Tandem: 2 wheels; up to 2 passengers // Tandem: 2 wheels; up to 2 passengers
@ -161,7 +159,7 @@ println("Tandem: \(tandem.description())")
下面的例子定义了`Vehicle`的一个新的子类,叫`Car`,它重写了从`Vehicle`类继承来的`description`方法: 下面的例子定义了`Vehicle`的一个新的子类,叫`Car`,它重写了从`Vehicle`类继承来的`description`方法:
``` ```swift
class Car: Vehicle { class Car: Vehicle {
var speed: Double = 0.0 var speed: Double = 0.0
init() { init() {
@ -184,7 +182,7 @@ class Car: Vehicle {
如果你创建一个`Car`的新实例,并打印`description`方法的输出,你就会发现描述信息已经发生了改变: 如果你创建一个`Car`的新实例,并打印`description`方法的输出,你就会发现描述信息已经发生了改变:
``` ```swift
let car = Car() let car = Car()
println("Car: \(car.description())") println("Car: \(car.description())")
// Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph // Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph
@ -200,13 +198,12 @@ println("Car: \(car.description())")
你可以将一个继承来的只读属性重写为一个读写属性,只需要你在重写版本的属性里提供 getter 和 setter 即可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。 你可以将一个继承来的只读属性重写为一个读写属性,只需要你在重写版本的属性里提供 getter 和 setter 即可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。
> 注意: > 注意:
>
如果你在重写属性中提供了 setter那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接返回`super.someProperty`来返回继承来的值。正如下面的`SpeedLimitedCar`的例子所示。 如果你在重写属性中提供了 setter那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接返回`super.someProperty`来返回继承来的值。正如下面的`SpeedLimitedCar`的例子所示。
以下的例子定义了一个新类,叫`SpeedLimitedCar`,它是`Car`的子类。类`SpeedLimitedCar`表示安装了限速装置的车它的最高速度只能达到40mph。你可以通过重写继承来的`speed`属性来实现这个速度限制: 以下的例子定义了一个新类,叫`SpeedLimitedCar`,它是`Car`的子类。类`SpeedLimitedCar`表示安装了限速装置的车它的最高速度只能达到40mph。你可以通过重写继承来的`speed`属性来实现这个速度限制:
``` ```swift
class SpeedLimitedCar: Car { class SpeedLimitedCar: Car {
override var speed: Double { override var speed: Double {
get { get {
@ -223,7 +220,7 @@ class SpeedLimitedCar: Car {
如果你尝试将`SpeedLimitedCar`实例的`speed`属性设置为一个大于40mph的数然后打印`description`函数的输出你会发现速度被限制在40mph 如果你尝试将`SpeedLimitedCar`实例的`speed`属性设置为一个大于40mph的数然后打印`description`函数的输出你会发现速度被限制在40mph
``` ```swift
let limitedCar = SpeedLimitedCar() let limitedCar = SpeedLimitedCar()
limitedCar.speed = 60.0 limitedCar.speed = 60.0
println("SpeedLimitedCar: \(limitedCar.description())") println("SpeedLimitedCar: \(limitedCar.description())")
@ -234,13 +231,12 @@ println("SpeedLimitedCar: \(limitedCar.description())")
你可以在属性重写中为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会被通知到,无论那个属性原本是如何实现的。关于属性观察器的更多内容,请看[属性观察器](../chapter2/_10Properties.html#property_observer)。 你可以在属性重写中为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会被通知到,无论那个属性原本是如何实现的。关于属性观察器的更多内容,请看[属性观察器](../chapter2/_10Properties.html#property_observer)。
> 注意: > 注意:
>
你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值是不可以被设置的,所以,为它们提供`willSet``didSet`实现是不恰当。此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已经为那个属性提供了定制的 setter那么你在 setter 中就可以观察到任何值变化了。 你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值是不可以被设置的,所以,为它们提供`willSet``didSet`实现是不恰当。此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已经为那个属性提供了定制的 setter那么你在 setter 中就可以观察到任何值变化了。
下面的例子定义了一个新类叫`AutomaticCar`,它是`Car`的子类。`AutomaticCar`表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位。`AutomaticCar`也提供了定制的`description`方法,可以输出当前挡位。 下面的例子定义了一个新类叫`AutomaticCar`,它是`Car`的子类。`AutomaticCar`表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位。`AutomaticCar`也提供了定制的`description`方法,可以输出当前挡位。
``` ```swift
class AutomaticCar: Car { class AutomaticCar: Car {
var gear = 1 var gear = 1
override var speed: Double { override var speed: Double {
@ -256,7 +252,7 @@ class AutomaticCar: Car {
当你设置`AutomaticCar``speed`属性,属性的`didSet`观察器就会自动地设置`gear`属性为新的速度选择一个合适的挡位。具体来说就是属性观察器将新的速度值除以10然后向下取得最接近的整数值最后加1来得到档位`gear`的值。例如速度为10.0时挡位为1速度为35.0时挡位为4 当你设置`AutomaticCar``speed`属性,属性的`didSet`观察器就会自动地设置`gear`属性为新的速度选择一个合适的挡位。具体来说就是属性观察器将新的速度值除以10然后向下取得最接近的整数值最后加1来得到档位`gear`的值。例如速度为10.0时挡位为1速度为35.0时挡位为4
``` ```swift
let automatic = AutomaticCar() let automatic = AutomaticCar()
automatic.speed = 35.0 automatic.speed = 35.0
println("AutomaticCar: \(automatic.description())") println("AutomaticCar: \(automatic.description())")
@ -271,3 +267,4 @@ println("AutomaticCar: \(automatic.description())")
如果你重写了`final`方法,属性或附属脚本,在编译时会报错。在扩展中,你添加到类里的方法,属性或附属脚本也可以在扩展的定义里标记为 final。 如果你重写了`final`方法,属性或附属脚本,在编译时会报错。在扩展中,你添加到类里的方法,属性或附属脚本也可以在扩展的定义里标记为 final。
你可以通过在关键字`class`前添加`@final`特性(`@final class`)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。 你可以通过在关键字`class`前添加`@final`特性(`@final class`)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。