Swift 继承

与其他面向对象语言一样,Swift 也支持类继承的概念。

继承允许我们从现有类创建新类。

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

Swift 继承语法

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

// define a superclass
class Animal {
  // properties and methods definition
}

// inheritance
class Dog: Animal {

  // properties and methods of Animal
  // properties and methods of Dog
}

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


示例:Swift 继承

class Animal {

  // properties and method of the parent class
  var name: String = ""

  func eat() {
    print("I can eat")
  }
}

// inherit from Animal
class Dog: Animal {

  // new method in subclass
  func display() {

    // access name property of superclass
    print("My name is ", name);
  }
}

// create an object of the subclass
var labrador = Dog()

// access superclass property and method 
labrador.name = "Rohu"
labrador.eat()

// call subclass method 
labrador.display()

输出

I can eat
My name is Rohu

在上面的示例中,我们从Animal超类派生了Dog子类。请注意以下语句:

labrador.name = "Rohu"

labrador.eat()

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

此外,我们在Dog类的`eat()`方法内访问了`name`属性。


is-a 关系

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

  1. **汽车**是**交通工具**
  2. **苹果**是**水果**
  3. 动物

在这里,汽车可以从交通工具继承,苹果可以从水果继承,等等。


Swift 继承中的方法重写

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

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

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

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

示例:方法重写

class Animal {

 // method in the superclass
 func eat() {
   print("I can eat")
 }
}

// Dog inherits Animal
class Dog: Animal {

  // overriding the eat() method
  override func eat() {
    print("I eat dog food")
  }
}

// create an object of the subclass
var labrador =  Dog()

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

输出

I eat dog food

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

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

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

override func eat() {
  print("I eat dog food")
}

Swift 继承中的 `super` 关键字

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

但是,如果我们想从子类访问超类的方法,我们使用super关键字。例如,

class Animal {

  // create method in superclass
  func eat() {
    print("I can eat")
  }
}

// Dog inherits Animal
class Dog: Animal {

  // overriding the eat() method
  override func eat() {

  // call method of superclass
  super.eat()
  print("I eat dog food")
  }
}

// create an object of the subclass
var labrador =  Dog()

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

输出

I can eat
I eat dog food

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

Dog类中,我们使用了

// call method of superclass
super.eat()

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

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

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

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


为什么要继承?

为了理解继承的好处,让我们考虑一个场景。

假设我们正在处理正多边形,如正方形、五边形等。并且,我们需要根据输入来计算这些多边形的周长。

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

class RegularPolygon {


  calculatePerimeter() {
    // code to compute perimeter
  }
}

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

class Square: RegularPolygon {

  var length = 0
  var sides = 0
}

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

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


示例:继承的好处

import Foundation
class RegularPolygon {

 func calculatePerimeter(length: Int, sides: Int) {
   var result = length * sides
   print("Perimeter:", result )
 }
}

// inherit Square from Polygon
class RegularSquare: RegularPolygon {
 var length = 0
 var sides = 0

 func calculateArea() {
   var area = length * length
   print("Regular Square Area:", area)
 }
}

// inherit Pentagon from Polygon
class RegularTriangle: RegularPolygon {
 var length = 0.0
 var sides = 0.0

 func calculateArea() {
   var area = (sqrt(3)/4) * (length * length)
   print("Regular Triangle Area:", area)
 }
}
var shape = RegularSquare()
shape.length = 4
shape.calculateArea()
shape.calculatePerimeter(length: 3,sides:4)

var shape2 = RegularTriangle()
shape2.length = 2
shape2.calculateArea()
shape2.calculatePerimeter(length: 2,sides:3)

输出

Regular Square Area: 16
Perimeter: 12
Regular Triangle Area: 1.7320508075688772
Perimeter: 6

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

在这里,RegularSquareRegularTriangle继承自RegularPolygon

正多边形周长的计算公式对所有多边形都通用,因此我们重用了超类的calculatePerimeter()方法。

由于面积的计算公式因形状而异,因此我们在子类中创建了一个单独的方法来计算面积。

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战