什么是继承?
继承是一种通过从已有类创建新类来扩展功能的方式。在这个过程中,新类会自动继承已有类的所有属性和方法,并可以根据需要添加或重写这些属性和方法以满足自身的需求。在Swift中,继承通过class
关键字来实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Vehicle {
var currentSpeed = 0.0
func accelerate() {
currentSpeed += 10.0
}
func brake() {
currentSpeed -= 10.0
}
}
class Bicycle: Vehicle {
var hasBasket = false
}
let bicycle = Bicycle()
bicycle.accelerate()
在上述代码中,我们定义了一个Vehicle
类来表示交通工具,包含当前速度属性和加速/刹车方法。之后,我们又定义了一个Bicycle
类,它从Vehicle
类继承而来,并增加了一个hasBasket
属性。最后,我们创建了一个Bicycle
实例,并调用其从Vehicle
继承而来的accelerate()
方法。
子类可以重写(override)父类的方法、属性和下标,以满足自身的需求。为了重写父类中的内容,子类需要使用override
关键字进行标记,并在子类中实现自己的版本。在这个过程中,子类可以访问父类中已有的实现,并在其基础上进行修改或扩展。
重写
方法重写
当子类需要重写父类的方法时,可以通过在子类中重新定义该方法来实现。在子类中,使用override
关键字来标记需要重写的方法,并且在参数列表和返回值类型上确保与父类中的方法一致。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Vehicle {
func makeNoise() {
print("Vroom vroom")
}
}
class Car: Vehicle {
override func makeNoise() {
print("Honk honk")
}
}
let car = Car()
car.makeNoise() // Output: Honk honk
在上述代码中,我们定义了一个Vehicle
类和一个Car
类。其中,Vehicle
类包含了一个makeNoise()
方法,而Car
类则从Vehicle
类继承而来,并重写了makeNoise()
方法。当我们创建一个Car
实例并调用其makeNoise()
方法时,输出结果为”Honk honk”,这表明Car
类成功地重写了父类中的方法。
属性重写
除了方法外,子类还可以重写父类中的属性。当子类需要重写父类的属性时,可以使用override
关键字,并在子类中重新定义该属性。在这个过程中,子类可以访问父类中已有的实现,并在其基础上进行修改或扩展。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Vehicle {
var speed: Double {
return 0.0
}
}
class Car: Vehicle {
override var speed: Double {
return 100.0
}
}
let car = Car()
print(car.speed) // Output: 100.0
在上述代码中,我们定义了一个Vehicle
类和一个Car
类。其中,Vehicle
类包含了一个speed
属性,而Car
类则从Vehicle
类继承而来,并重写了speed
属性。当我们创建一个Car
实例并调用其speed
属性时,输出结果为100.0,这表明Car
类成功地重写了父类中的属性。
下标重写
在Swift中,子类同样可以重写父类的下标。当子类需要重写父类的下标时,可以使用override
关键字,并在子类中重新定义该下标。在这个过程中,子类可以访问父类中已有的实现,并在其基础上进行修改或扩展。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Vehicle {
subscript(index: Int) -> String {
return "Super vehicle"
}
}
class Car: Vehicle {
override subscript(index: Int) -> String {
return "Super car"
}
}
let car = Car()
print(car[0]) // Output: Super car
在上述代码中,我们定义了一个Vehicle
类和一个Car
类。其中,Vehicle
类包含了一个下标,而Car
类则从Vehicle
类继承而来,并重写了该下标。当我们创建一个Car
实例并调用其下标时,输出结果为”Super car”,这表明Car
类成功地重写了父类中的下标。
继承的优点
继承作为一种面向对象编程的基础概念,在Swift中同样有着许多优点:
- 代码复用性: 继承可以让子类自动拥有父类的属性和方法,减少了代码重复的情况,也方便了代码的维护和修改。
- 代码灵活度: 子类可以根据需要对父类的属性和方法进行重写或添加,使得代码更加适应不同的场景。
- 代码可扩展性: 继承可以通过创建子类并在其中添加新方法或属性,来扩展已有类的功能。
- 代码组织性: 继承可以将相似的对象归为一类,方便后续的管理和维护。
继承的限制
尽管继承非常有用,但是在使用时仍然需要考虑一些限制和注意事项。
- 继承链的长度: 过长的继承链可能会导致代码变得难以理解和维护,因此应该尽量避免过度继承的情况。
- 构造器的要求: 如果子类没有定义任何指定构造器,那么它会自动继承所有父类的指定构造器。如果父类中只定义了便利构造器,则子类必须实现至少一个指定构造器以确保初始化安全性。
- 方法重载的影响: 如果子类重载了一个父类的方法,那么在调用该方法时需要特别小心。这是因为子类的实例也可以看做是父类的实例,因此在某些情况下可能会出现意料之外的结果。
- 属性观察者的限制: 子类无法为继承来的属性添加属性观察者,但是可以重写已有的属性并为其添加属性观察者。
继承的实践
接下来介绍一些使用继承的实践技巧。
使用super
关键字
在子类中,如果需要访问父类中的属性或方法,可以使用super
关键字来实现。具体而言,super
可以用于:
- 在子类中调用父类中的指定构造器。
- 在子类中调用父类中的方法、属性、下标等。
- 在重载父类方法时调用父类的实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Person {
var name: String
init(name: String) {
self.name = name
}
func introduce() {
print("My name is \(name)")
}
}
class Student: Person {
var grade: Int
init(name: String, grade: Int) {
self.grade = grade
super.init(name: name)
}
override func introduce() {
super.introduce()
print("I am a student in grade \(grade)")
}
}
let student = Student(name: "Tom", grade: 5)
student.introduce()
在上述代码中,我们定义了一个Person
类和一个Student
类。其中,Student
类从Person
类继承而来,并增加了一个grade
属性。在Student
类中,我们通过调用super.init(name:)
来调用父类的指定构造器,以确保子类初始化完成。在Student
类中,我们还重写了父类的introduce()
方法,并通过super.introduce()
来调用父类中的实现。
使用final关键字
在Swift中,如果不希望某个类被其他类继承,则可以使用final
关键字来修饰该类。这样一来,在其他类中尝试继承该类时,编译器会报错。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
final class Vehicle {
var currentSpeed = 0.0
func accelerate() {
currentSpeed += 10.0
}
func brake() {
currentSpeed -= 10.0
}
}
class Bicycle: Vehicle { // Error: Inheritance from a final class 'Vehicle'
var hasBasket = false
}
在上述代码中,我们将Vehicle
类声明为final
,因此在Bicycle
类中尝试继承它时,编译器会报错。
使用多层继承
在Swift中,子类也可以作为父类再次被继承,从而形成更加复杂的继承结构。例如,我们可以定义一个Car
类,它从Vehicle
类继承而来,并增加了一些新的属性和方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Car: Vehicle {
var brand: String
init(brand: String) {
self.brand = brand
}
func honk() {
print("\(brand) car honks")
}
}
let car = Car(brand: "BMW")
car.accelerate()
car.honk()
在上述代码中,我们定义了一个Car
类,它从Vehicle
类继承而来,并增加了一个brand
属性和一个honk()
方法。通过对Car
类进行定义,我们成功地创建了一个多层继承的继承结构。