Swift 继承

在本教程中,我们将通过实例学习 Swift 继承及其类型。

与其他 OOP 语言一样,Swift 也支持类继承的概念。

继承让我们可以从现有类创建新类。

创建的新类称为子类(子类或派生类),派生子类的现有类称为超类(父类或基类)。

Swift 继承语法

在 Swift 中,我们使用冒号 : 从另一个类继承一个类。例如,

  1. // define a superclass
  2. class Animal {
  3. // properties and methods definition
  4. }
  5. // inheritance
  6. class Dog: Animal {
  7. // properties and methods of Animal
  8. // properties and methods of Dog
  9. }

这里,我们从 Animal 超类继承了 Dog 子类。

实例:继承
  1. class Animal {
  2. // properties and method of the parent class
  3. var name: String = ""
  4. func eat() {
  5. print("I can eat")
  6. }
  7. }
  8. // inherit from Animal
  9. class Dog: Animal {
  10. // new method in subclass
  11. func display() {
  12. // access name property of superclass
  13. print("My name is ", name);
  14. }
  15. }
  16. // create an object of the subclass
  17. var labrador = Dog()
  18. // access superclass property and method
  19. labrador.name = "Rohu"
  20. labrador.eat()
  21. // call subclass method
  22. labrador.display()

结果如下:

  1. I can eat
  2. My name is Rohu

在上面的例子中,我们从一个超类 Animal 派生了一个子类 Dog。注意这些语句,

  1. labrador.name = "Rohu"
  2. labrador.eat()

这里,我们使用 labradorDog 的对象)访问 Animal 类的 nameeat()。这是可以的,因为子类继承超类的所有属性和方法。

此外,我们还访问了 Dog 类方法中的 name 属性。


is-a 关系

在 Swift 中,继承是一种 is-a 关系。也就是说,只有当两个类之间存在 is-a 关系时,我们才使用继承。例如,

  • Car is a Vehicle(汽车是一辆汽车)
  • Apple is a Fruit(苹果是一种水果)
  • Cat is an Animal(猫是一种动物)

在这里,Car 可以继承 VehicleApple 可以继承 Fruit,等等。


Swift 继承中的方法重写

在前面的例子中,我们看到子类的对象可以访问超类的方法。

然而,如果在超类和子类中都存在相同的方法怎么办?

在这种情况下,子类中的方法将覆盖超类中的该方法。这个概念在 Swift 中称为方法重写。

我们使用 override 关键字告诉编译器我们正在重写一个方法。

实例:方法重写
  1. class Animal {
  2. // method in the superclass
  3. func eat() {
  4. print("I can eat")
  5. }
  6. }
  7. // Dog inherits Animal
  8. class Dog: Animal {
  9. // overriding the eat() method
  10. override func eat() {
  11. print("I eat dog food")
  12. }
  13. }
  14. // create an object of the subclass
  15. var labrador = Dog()
  16. // call the eat() method
  17. labrador.eat()

结果如下:

  1. I eat dog food

在上面的实例中,Dog 类和 Animal 类中都存在相同的方法 eat()

现在,当我们使用 Dog 子类的对象调用 eat() 方法时,会调用 Dog 类的方法。

这是因为 Dog 子类的 eat() 方法重写了 Animal 超类的相同方法。我们已经使用 override 关键字指定重写方法。

  1. override func eat() {
  2. print("I eat dog food")
  3. }

Swift 继承中的 super 关键字

之前我们看到子类中的相同方法重写了超类中的方法。

然而,如果我们需要从子类访问超类方法,我们将使用 super 关键字。例如,

  1. class Animal {
  2. // create method in superclass
  3. func eat() {
  4. print("I can eat")
  5. }
  6. }
  7. // Dog inherits Animal
  8. class Dog: Animal {
  9. // overriding the eat() method
  10. override func eat() {
  11. // call method of superclass
  12. super.eat()
  13. print("I eat dog food")
  14. }
  15. }
  16. // create an object of the subclass
  17. var labrador = Dog()
  18. // call the eat() method
  19. labrador.eat()

结果如下:

  1. I can eat
  2. I eat dog food

在上面的例子中,Dog 子类的 eat() 方法重写了 Animal 超类的相同方法。

Dog 类中,我们使用了

  1. // call method of superclass
  2. super.eat()

Dog 子类调用 Animal 超类的 eat() 方法。

因此,当我们使用 labrador 对象调用 eat() 方法时

  1. // call the eat() method
  2. labrador.eat()

执行 eat() 方法的重写版本和超类版本。


为什么要使用继承?

为了理解继承的好处,让我们考虑一种情况。

假设我们正在处理正方形、五边形等规则多边形。并且,我们必须根据输入找到这些多边形的周长。

1.由于计算周长的公式对于所有规则多边形都是通用的,因此我们可以创建一个 Polygon 类和一个 calculatePerimeter() 方法来计算周长。

  1. class RegularPolygon {
  2. calculatePerimeter() {
  3. // code to compute perimeter
  4. }
  5. }

2.并从 RegularPolygon 类继承 SquarePentagon 类。这些类中的每一个都有属性来存储边的长度和数量,因为它们对于所有多边形都是不同的。

  1. class Square: RegularPolygon {
  2. var length = 0
  3. var sides = 0
  4. }

我们将 lengthsides 的值传递给 calculatePerimeter() 以计算周长。

这就是继承如何使我们的代码可重用和更直观。

实例:继承的优势
  1. import Foundation
  2. class RegularPolygon {
  3. func calculatePerimeter(length: Int, sides: Int) {
  4. var result = length * sides
  5. print("Perimeter:", result )
  6. }
  7. }
  8. // inherit Square from Polygon
  9. class RegularSquare: RegularPolygon {
  10. var length = 0
  11. var sides = 0
  12. func calculateArea() {
  13. var area = length * length
  14. print("Regular Square Area:", area)
  15. }
  16. }
  17. // inherit Pentagon from Polygon
  18. class RegularTriangle: RegularPolygon {
  19. var length = 0.0
  20. var sides = 0.0
  21. func calculateArea() {
  22. var area = (sqrt(3)/4) * (length * length)
  23. print("Regular Triangle Area:", area)
  24. }
  25. }
  26. var shape = RegularSquare()
  27. shape.length = 4
  28. shape.calculateArea()
  29. shape.calculatePerimeter(length: 3,sides:4)
  30. var shape2 = RegularTriangle()
  31. shape2.length = 2
  32. shape2.calculateArea()
  33. shape2.calculatePerimeter(length: 2,sides:3)

结果如下:

  1. Regular Square Area: 16
  2. Perimeter: 12
  3. Regular Triangle Area: 1.7320508075688772
  4. Perimeter: 6

在上面的实例中,我们创建了一个 RegularPolygon 类,用于计算正多边形的周长。

这里,RegularSquareRegularTriangle 继承自 RegularPolygon

计算正多边形参数的公式对所有人来说都是通用的,因此我们重用了超类的 calculatePerimeter() 方法。

由于计算面积的公式对于不同的形状是不同的,所以我们在子类中创建了一个单独的方法来计算面积。