A class can inherit methods, properties, and other characteristics from another class. When one class inherits from another, the inheriting class is known as a subclass, and the class it inherits from is known as its superclass.
一个类可以从另外一个类中继承方法,属性以及其他特性。当一个类继承另外一个类时,这个类被称作为子类,而被继承的类被称作为父类。
Inheritance is a fundamental behavior that differentiates classes from other types in Swift. Classes in Swift can call and access methods, properties, and subscripts belonging to their superclass and can provide their own overriding versions of those methods, properties, and subscripts to refine or modify their behavior. Swift helps to ensure your overrides are correct by checking that the override definition has a matching superclass definition.
在Swift语言中,继承是区分类与其他类型的一个基本行为。一个类可以访问并调用其父类中的方法、属性和下标,也可以通过重写它们来修改或优化它们的行为。Swift通过检查重写的定义是否能与一个父类中的定义匹配来确保重写的正确性。
Classes can also add property observers to inherited properties in order to be notified when the value of a property changes. Property observers can be added to any property, regardless of whether it was originally defined as a stored or computed property.
类也可以通过对继承的属性添加观察器来监听它们的变化。属性观察器可以被添加用于监听任何属性,无论被监听的属性最初是被定义为存储属性还是计算属性。
Any class that does not inherit from another class is known as a base class. 一个没有继承其他类的类被称为基类。
NOTE
Swift classes do not inherit from a universal base class. Classes you define without specifying a superclass automatically become base classes for you to build upon.
注意
Swift中的类没有继承一个全局的基类。没有指定父类的类会自动成为一个可用来被扩展的基类。
The example below defines a base class called Vehicle
. This base class declares two properties(numberOfWheels
and maxPassengers
) that are universal to all vehicles. These properties are used by a method called description
, which returns a String
description of the vehicle’s characteristics:
下面的例子定义了一个基类Vehicle
。类中声明了两个所有车辆都通用的属性(numberOfWheels
和maxPassengers
)。这两个属性在方法description
中被使用,这个方法返回一个String
类型的值来描述车辆的特性:
class Vehicle {
var numberOfWheels: Int
var maxPassengers: Int
func description() -> String {
return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers"
}
init() {
numberOfWheels = 0
maxPassengers = 1
}
}
The Vehicle
class also defines an initializer to set up its properties. Initializers are described in detail in Initialization, but a brief introduction is required here in order to illustrate how inherited properties can be modified by subclasses.
Vehicle
类中还定义了一个构造器来初始化它的属性。构造器在构造过程章节中有详细描述,不过在这里会简单介绍一下被继承的属性是如何被子类修改的。
You use initializers to create a new instance of a type. Although initializers are not methods, they are written in a very similar syntax to instance methods. An initializer prepares a new instance for use, and ensures that all properties of the instance have valid initial values.
构造器会被用来创建一个类型的实例。尽管构造器并不是方法,但是书写它们的语法和实例方法非常类似。构造器准备一个新的实例供使用,并确保实例中所有的属性都有合法的初始值。
In its simplest form, an initializer is like an instance method with no parameters, written using the init
keyword:
在最简单的形式中,构造器就像是一个没有参数的实例方法,用关键词init
来声明:
init() {
// perform some initialization here
}
To create a new instance of Vehicle
, call this initializer with initializer syntax, written as TypeName
followed by empty parentheses:
创建一个Vehicle
类实例需要通过使用构造器语法来调用构造器,写法是在类名后加上一对空的括号:
let someVehicle = Vehicle()
The initializer for Vehicle
sets some initial property values (numberOfWheels = 0
and maxPassengers = 1
) for an arbitrary vehicle.
Vehicle
类的构造器为一个车辆初始化了一些属性(numberOfWheels = 0
和 maxPassengers = 1
)。
The Vehicle
class defines common characteristics for an arbitrary vehicle, but is not much use in itself. To make it more useful, you need to refine it to describe more specific kinds of vehicle.
Vehicle类
为车辆定义了一些公用的特性,但是这些特性对类本身来说并没有太多作用。为了提高这些特性的可用性,需要描述更多不同特定种类的车辆。
Subclassing is the act of basing a new class on an existing class. The subclass inherits characteristics from the existing class, which you can refine. You can also add new characteristics to the subclass.
子类化是指在一个已有类的基础上建立一个新的类。新建的子类会继承已有类的特性,并可以优化它们。在子类中还可以增加新的特性。
To indicate that a class has a superclass, write the superclass name after the original class name, separated by a colon:
当声明一个类的父类时,需要将父类的名字写在原有类之后,并用冒号分隔:
class SomeClass: SomeSuperclass {
// class definition goes here
}
The next example defines a second, more specific vehicle called Bicycle
. This new class is based on the existing capabilities of Vehicle
. You indicate this by placing the name of the class the subclass builds upon (Vehicle
) after its own name (Bicycle
), separated by a colon.
下面的例子定义了另一个更具体的车辆类Bicycle
。新定义的类基于Vehicle
类中存在的功能。定义的时候需要把父类的名字(Vehicle
)放在新定义类的名字(Bicycle
)之后,并用冒号分隔。
This can be read as:
“Define a new class called Bicycle
, which inherits the characteristics of Vehicle
”:
下面的语句可以这样来解读:
“定义一个新的名为Bicycle
的类,它继承了Vehicle
类的特性。”
class Bicycle: Vehicle {
init() {
super.init()
numberOfWheels = 2
}
}
Bicycle
is a subclass of Vehicle
, and Vehicle
is the superclass of Bicycle
. The new Bicycle
class automatically gains all characteristics of Vehicle
, such as its maxPassengers
and numberOfWheels
properties.You can tailor those characteristics and add new ones to better match the requirements of the Bicycle
class.
Bicycle
是Vehicle
的子类, 反而言之Vehicle
是Bicycle
的父类。新创建的Bicycle
类自动获得了Vehicle
类的所有特性,比如它的maxPassengers
与numberOfWheels
属性。为了更好的满足Bicycle
类的需求,你可以修改这些特性或者增加新的特性。
The Bicycle
class also defines an initializer to set up its tailored characteristics. The initializer for Bicycle
calls super.init()
, the initializer for the Bicycle
class’s superclass, Vehicle
, and ensures that all of the inherited properties are initialized by Vehicle
before Bicycle
tries to modify them.
Bicycle
类同样定义了一个构造器来初始化其修改过的特性。Bicycle
的构造器通过调用其父类Vehicle
的构造器super.init()
来确保所有继承下来的属性在被修改前都已被Vehicle
类成功初始化。
Note
Unlike Objective-C, initializers are not inherited by default in Swift. For more information, see [Initializer
Inheritance and Overriding]().
注意
与Objective-C不同的是,在Swift中构造器是不会默认被继承的。更多信息请参考[构造器的继承和重写]()。
The default value of maxPassengers
provided by Vehicle
is already correct for a bicycle, and so it is not changed within the initializer for Bicycle
. The original value of numberOfWheels
is not correct, however, and is replaced with a new value of 2
.
Vehicle
类中为maxPassengers
提供的默认值对于一辆自行车来说已经是正确的了,所以在Bicycle
类的构造器中没有做修改。而numberOfWheels
的原始值对于一辆自行车来说是错误的,所以它被替换成了一个新的值2
。
As well as inheriting the properties of Vehicle
, Bicycle
also inherits its methods. If you create an instance of Bicycle
, you can call its inherited description
method to see how its properties have been updated:
除了继承了Vehicle
类中的属性,Bicycle
类还继承了它的方法。创建了一个Bicycle
的实例后,可以通过调用它继承过来的description
方法来观察类中属性的更新:
let bicycle = Bicycle()
println("Bicycle: \(bicycle.description())")
// Bicycle: 2 wheels; up to 1 passengers
Subclasses can themselves be subclassed:
子类可以被继续继承:
class Tandem: Bicycle {
init() {
super.init()
maxPassengers = 2
}
}
This example creates a subclass of Bicycle
for a two-seater bicycle known as a “tandem”. Tandem
inherits the two properties from Bicycle
, which in turn inherits these properties from Vehicle
. Tandem
doesn’t change the number of wheels—it’s still a bicycle, after all—but it does update maxPassengers
to have the correct value for a tandem.
上面的例子创建了一个Bicycle
类的子类双人自行车Tandem
。Tandem
类继承了Bicycle
类中的两个属性,而这两个属性又是从Vehicle
类继承下来的。由于Tandem
仍然是自行车的一种,所以类中没有改变车轮数量的属性numberOfWheels
,但是它更新了表示最大乘客数的属性maxPassengers
以满足一辆双人自行车的要求。
NOTE
Subclasses are only allowed to modify variable properties of superclasses during initialization. You can’t
modify inherited constant properties of subclasses.
注意
在初始化过程中,子类只允许修改父类中的变量属性,而常量属性是不能被修改的。
Creating an instance of Tandem
and printing its description shows how its properties have been updated:
下面通过创建一个Tandem
的实例并打印其描述来观察它的属性更新:
let tandem = Tandem()
println("Tandem: \(tandem.description())")
// Tandem: 2 wheels; up to 2 passengers
Note that the description
method is also inherited by Tandem
. Instance methods of a class are inherited by any and all subclasses of that class.
注意description
方法也是Tandem
类继承下来的。一个类中的实例方法会被它所有的子类继承。
A subclass can provide its own custom implementation of an instance method, class method, instance property, or subscript that it would otherwise inherit from a superclass. This is known as overriding.
子类可以为继承过来的实例方法、类方法、实例属性或下标提供它自己的实现,这个行为被称作重写。
To override a characteristic that would otherwise be inherited, you prefix your overriding definition with the override
keyword. Doing so clarifies that you intend to provide an override and have not provided a matching definition by mistake. Overriding by accident can cause unexpected behavior, and any overrides without the override
keyword are diagnosed as an error when your code is compiled.
如果要重写某个属性,你需要在重写的定义前加上override
关键字。这么做是为了表明你是为了提供一个重写的版本而不是错误地提供了一个同样的定义。意外地重写会引起不可预知的错误,没有加关键字override
的重写都会在编译时被诊断为错误。
The override
keyword also prompts the Swift compiler to check that your overriding class’s superclass (or one of its parents) has a declaration that matches the one you provided for the override. This check ensures that your overriding definition is correct.
override
关键字也会提醒Swift编译器去校验被继承的父类(或其中中一个父类)中是否有匹配的声明用于被重写。这个检查可以确保你的重写定义是正确的。
When you provide a method, property, or subscript override for a subclass, it is sometimes useful to use the existing superclass implementation as part of your override. For example, you can refine the behavior of that existing implementation or store a modified value in an existing inherited variable.
当你访问父类的方法、属性或下标时,有时在你的重写版本中使用已存在的父类实现会很有用。比如你可以优化一个已有的实现或者在一个继承来的变量重储存一个修改过的值。
Where this is appropriate, you access the superclass version of a method, property, or subscript by using the super
prefix:
在适当的地方,你可以通过super
前缀来访问父类版本的方法、属性或下标:
someMethod
can call the superclass version of someMethod
by calling super.someMethod()
within the overriding method implementation.someProperty
can access the superclass version of someProperty
as super.someProperty
within the overriding getter or setter implementation.An overridden subscript for someIndex
can access the superclass version of the same subscript as super[someIndex]
from within the overriding subscript implementation.
一个重写的方法someMethod
可以在方法实现中通过super.someMethod()
来调用父类版本的someMethod
。
someProperty
可以在getter和setter方法的重写实现中通过super.someProperty
来访问父类版本的someProperty
。someIndex
可以在实现中通过super[someIndex]
来调用相同下标的父类版本的。You can override an inherited instance or class method to provide a tailored or alternative implementation of the method within your subclass.
在子类中你可以通过提供一个定制或替代的实现来重写一个继承过来的实例方法或类方法。
The following example defines a new subclass of Vehicle
called Car
, which overrides the description
method it inherits from Vehicle
:
下面的例子定义了Vehicle
类的一个新子类Car
, 子类中重写了从父类中继承过来的方法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
declares a new stored Double
property called speed
. This property defaults to 0.0
, meaning “zero miles per hour”. Car
also has a custom initializer, which sets the maximum number of passengers to 5
, and the default number of wheels to 4
.
Car
类中声明了一个新的Double
类存储型属性speed
,默认值是0.0
,代表”时速为每小时0英里”。Car类还有自定义构造器,构造器中设置最大乘客量为5
,默认车轮数为4
。
Car
overrides its inherited description
method by providing a method with the same declaration as the description
method from Vehicle
. The overriding method definition is prefixed with the override
keyword.
Car
类重写了继承来的description
方法,它的声明和父类Vehicle
中一致。被重写的方法定义前加上了override
关键字。
Rather than providing a completely custom implementation of description
, the overriding method actually starts by calling super.description
to retrieve the description provided by Vehicle
. It then appends some additional information about the car’s current speed.
重写的方法并没有完全自定义方法description
的实现,它在开始时通过调用super.description
来使用父类Vehicle
中的方法实现,之后再为车辆的当前速度追加了一些额外信息。
If you create a new instance of Car
, and print the output of its description
method, you can see that the description has indeed changed:
如果你创建一个Car
类的实例,并打印description
方法的输出,你会发现描述的信息已经发生了改变:
let car = Car()
println("Car: \(car.description())")
// Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph
You can override an inherited instance or class property to provide your own custom getter and setter for that property, or to add property observers to enable the overriding property to observe when the underlying property value changes.
你可以重写继承来的实例属性或类属性来提供自定义的getter和setter方法,或添加属性观察器来使被重写的属性观察属性值什么时候发生改变。
You can provide a custom getter (and setter, if appropriate) to override any inherited property, regardless of whether the inherited property is implemented as a stored or computed property at its source. The stored or computed nature of an inherited property is not known by a subclass—it only knows that the inherited property has a certain name and type. You must always state both the name and the type of the property you are overriding, to enable the compiler to check that your override matches a superclass property with the same name and type.
你可以提供自定义的getter(或setter,如适用)来重写任何被继承的属性,无论被继承的属性是存储型的还是计算型的。子类并不知道继承来的属性是存储型的还是计算型的,它只知道继承来的属性有名字和类型。在你重写一个属性时,必须声明它的名字和类型。这是为了让编译器检测你重写的属性在父类中有相同的名字和类型。
You can present an inherited read-only property as a read-write property by providing both a getter and a setter in your subclass property override. You cannot, however, present an inherited read-write property as a read-only property.
你可以通过提供getter和setter来将继承来的一个只读属性重写为一个读写属性。但是你无法将一个继承来的读写属性重写成一个只读属性。
NOTE
If you provide a setter as part of a property override, you must also provide a getter for that override. If you don’t want to modify the inherited property’s value within the overriding getter, you can simply pass through the inherited value by returning `super.someProperty` from the getter, as in the `SpeedLimitedCar` example below.
注意
如果你在重写时为一个属性提供了setter,那么你必须同时要提供一个getter。如果你不想在重写版本的getter中修改继承来的属性值,你可以直接返回`super.someProperty`,正如下面`SpeedLimitedCar`的例子所示。
The following example defines a new class called SpeedLimitedCar
, which is a subclass of Car
. The SpeedLimitedCar
class represents a car that has been fitted with a speed-limiting device, which prevents the car from traveling faster than 40mph. You implement this limitation by overriding the inherited speed
property:
下面的例子定义了一个新的类SpeedLimitedCar
,这个类是Car
类的子类。SpeedLimitedCar
类表示安装了限速装置的车来防止车的时速超过40英里。你需要通过重写speed
属性来实现这个速度限制:
class SpeedLimitedCar: Car {
override var speed: Double {
get {
return super.speed
}
set {
super.speed = min(newValue, 40.0)
}
}
}
Whenever you set the speed
property of a SpeedLimitedCar
instance, the property’s setter implementation checks the new value and limits it to 40mph. It does this by setting the underlying speed
property of its superclass to be the smaller of newValue
and 40.0
. The smaller of these two values is determined by passing them to the min
function, which is a global function provided by the Swift standard library. The min
function takes two or more values and returns the smallest one of those values.
当你设置一个SpeedLimitedCar
实例的speed
属性时,属性的setter
方法会检验新设置的值并把它限制在时速40英里以内,这是通过选择新设置的值和40之间最小的值来实现的。这个比较会通过调用min
函数实现,它是Swift标准库中的一个方法。min
函数接受两个或更多的参数并返回其中最小的一个。
If you try to set the speed
property of a SpeedLimitedCar
instance to more than 40mph, and then print the output of its description
method, you see that the speed has been limited:
如果你尝试将SpeedLimitedCar
实例中的speed
属性设置成时速40英里以上,然后打印description
方法的输出,你会看到车速已经被限制了:
let limitedCar = SpeedLimitedCar()
limitedCar.speed = 60.0
println("SpeedLimitedCar: \(limitedCar.description())")
// SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph
You can use property overriding to add property observers to an inherited property. This enables you to be notified when the value of the inherited property changes, regardless of how that property was originally implemented. For more information on property observers, see Property Observers.
你可以在属性重写时为一个继承来的属性添加属性观察器。当继承来的属性被修改时,你就会被通知到,无论那个属性原来是如何被实现的。关于属性观察器的更多内容,请参考属属性观察器。
NOTE
You cannot add property observers to inherited constant stored properties or inherited read-only computed properties. The value of these properties cannot be set, and so it is not appropriate to provide a `willSet` or `didSet` implementation as part of an override.
Note also that you cannot provide both an overriding setter and an overriding property observer. If you want to observe changes to a property’s value, and you are already providing a custom setter for that property, you can simply observe any value changes from within the custom setter.
注意
你不可以为继承来的常量存储型属性或只读计算型属性添加属性观察器。这些属性的值是不可以被修改的,所以在重写时为它们提供`willSet`和`didSet`的实现是不恰当的。
注意你不能同时提供重写的setter方法和属性观察期。如果你想要观察属性值的变化,并且你已经给那个属性提供了定制的setter方法,在setter方法中你就已经可以观察到任何属性值的变化了。
The following example defines a new class called AutomaticCar
, which is a subclass of Car
. The AutomaticCar
class represents a car with an automatic gearbox, which automatically selects an appropriate gear to use based on the current speed. AutomaticCar
also provides a custom description
method to print the current gear.
下面的例子定义了一个新类AutomaticCar
,它是Car
类的子类。AutomaticCar
类表示自动档汽车,它会根据当前的车速选择一个合适的档位。AutomaticCar
提供了一个定制的description
方法来输出当前的档位。
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)"
}
}
Whenever you set the speed
property of an AutomaticCar
instance, the property’s didSet
observer automatically sets the gear
property to an appropriate choice of gear for the new speed. Specifically, the property observer chooses a gear which is the new speed
value divided by 10
, rounded down to the nearest integer, plus 1
. A speed of 10.0
produces a gear of 1
, and a speed of 35.0
produces a gear of 4
:
当你为一个AutomaticCar
实例设置speed
属性时,属性的didSet
观察器会自动设置gear
属性到一个合适的档位。具体的计算方法是,属性观察者将新设置的速度值除以10
,向下取整之后再加1
。例如速度是10
的时候档位是1
,速度是35.0
的时候档位是4
:
let automatic = AutomaticCar()
automatic.speed = 35.0
println("AutomaticCar: \(automatic.description())")
// AutomaticCar: 4 wheels; up to 5 passengers; traveling at 35.0 mph in gear 4
You can prevent a method, property, or subscript from being overridden by marking it as final. Do this by writing the @final
attribute before its introducer keyword (such as @final var
, @final func
, @final class func
, and @final subscript
).
你可以通过标记一个属性、方法或下标为final来防止它们被重写。具体方法是在声明它们的关键字前加上@final
(例如@final var
, @final func
, @final class func
及@final subscript
)。
Any attempts to override a final method, property, or subscript in a subclass are reported as a compile-time error. Methods, properties or subscripts that you add to a class in an extension can also be marked as final within the extension’s definition.
如果被标记为final的方法、属性或下标在子类中被尝试重写,在编译时便会报错。在扩展时被添加到类中的方法,属性或附属脚本也可以在扩展的定义中标记为final。
You can mark an entire class as final by writing the @final
attribute before the class
keyword in its class definition (@final class
). Any attempts to subclass a final class will be reported as a compile-time error.
你也可以通过在关键字class前添加@final
属性(@final class
)来把整个类标记为final。如此一来这个类就不可以被继承,否则在编译时会报错。