Swift 继承
在本教程中,我们将通过实例学习 Swift 继承及其类型。
与其他 OOP 语言一样,Swift 也支持类继承的概念。
继承让我们可以从现有类创建新类。
创建的新类称为子类(子类或派生类),派生子类的现有类称为超类(父类或基类)。
Swift 继承语法
在 Swift 中,我们使用冒号 : 从另一个类继承一个类。例如,
// define a superclassclass Animal {// properties and methods definition}// inheritanceclass Dog: Animal {// properties and methods of Animal// properties and methods of Dog}
这里,我们从 Animal 超类继承了 Dog 子类。
实例:继承
class Animal {// properties and method of the parent classvar name: String = ""func eat() {print("I can eat")}}// inherit from Animalclass Dog: Animal {// new method in subclassfunc display() {// access name property of superclassprint("My name is ", name);}}// create an object of the subclassvar labrador = Dog()// access superclass property and methodlabrador.name = "Rohu"labrador.eat()// call subclass methodlabrador.display()
结果如下:
I can eatMy name is Rohu
在上面的例子中,我们从一个超类 Animal 派生了一个子类 Dog。注意这些语句,
labrador.name = "Rohu"labrador.eat()
这里,我们使用 labrador(Dog 的对象)访问 Animal 类的 name 和 eat()。这是可以的,因为子类继承超类的所有属性和方法。
此外,我们还访问了 Dog 类方法中的 name 属性。
is-a 关系
在 Swift 中,继承是一种 is-a 关系。也就是说,只有当两个类之间存在 is-a 关系时,我们才使用继承。例如,
- Car is a Vehicle(汽车是一辆汽车)
- Apple is a Fruit(苹果是一种水果)
- Cat is an Animal(猫是一种动物)
在这里,Car 可以继承 Vehicle,Apple 可以继承 Fruit,等等。
Swift 继承中的方法重写
在前面的例子中,我们看到子类的对象可以访问超类的方法。
然而,如果在超类和子类中都存在相同的方法怎么办?
在这种情况下,子类中的方法将覆盖超类中的该方法。这个概念在 Swift 中称为方法重写。
我们使用 override 关键字告诉编译器我们正在重写一个方法。
实例:方法重写
class Animal {// method in the superclassfunc eat() {print("I can eat")}}// Dog inherits Animalclass Dog: Animal {// overriding the eat() methodoverride func eat() {print("I eat dog food")}}// create an object of the subclassvar labrador = Dog()// call the eat() methodlabrador.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 superclassfunc eat() {print("I can eat")}}// Dog inherits Animalclass Dog: Animal {// overriding the eat() methodoverride func eat() {// call method of superclasssuper.eat()print("I eat dog food")}}// create an object of the subclassvar labrador = Dog()// call the eat() methodlabrador.eat()
结果如下:
I can eatI eat dog food
在上面的例子中,Dog 子类的 eat() 方法重写了 Animal 超类的相同方法。
在 Dog 类中,我们使用了
// call method of superclasssuper.eat()
从 Dog 子类调用 Animal 超类的 eat() 方法。
因此,当我们使用 labrador 对象调用 eat() 方法时
// call the eat() methodlabrador.eat()
执行 eat() 方法的重写版本和超类版本。
为什么要使用继承?
为了理解继承的好处,让我们考虑一种情况。
假设我们正在处理正方形、五边形等规则多边形。并且,我们必须根据输入找到这些多边形的周长。
1.由于计算周长的公式对于所有规则多边形都是通用的,因此我们可以创建一个 Polygon 类和一个 calculatePerimeter() 方法来计算周长。
class RegularPolygon {calculatePerimeter() {// code to compute perimeter}}
2.并从 RegularPolygon 类继承 Square 和 Pentagon 类。这些类中的每一个都有属性来存储边的长度和数量,因为它们对于所有多边形都是不同的。
class Square: RegularPolygon {var length = 0var sides = 0}
我们将 length 和 sides 的值传递给 calculatePerimeter() 以计算周长。
这就是继承如何使我们的代码可重用和更直观。
实例:继承的优势
import Foundationclass RegularPolygon {func calculatePerimeter(length: Int, sides: Int) {var result = length * sidesprint("Perimeter:", result )}}// inherit Square from Polygonclass RegularSquare: RegularPolygon {var length = 0var sides = 0func calculateArea() {var area = length * lengthprint("Regular Square Area:", area)}}// inherit Pentagon from Polygonclass RegularTriangle: RegularPolygon {var length = 0.0var sides = 0.0func calculateArea() {var area = (sqrt(3)/4) * (length * length)print("Regular Triangle Area:", area)}}var shape = RegularSquare()shape.length = 4shape.calculateArea()shape.calculatePerimeter(length: 3,sides:4)var shape2 = RegularTriangle()shape2.length = 2shape2.calculateArea()shape2.calculatePerimeter(length: 2,sides:3)
结果如下:
Regular Square Area: 16Perimeter: 12Regular Triangle Area: 1.7320508075688772Perimeter: 6
在上面的实例中,我们创建了一个 RegularPolygon 类,用于计算正多边形的周长。
这里,RegularSquare 和 RegularTriangle 继承自 RegularPolygon。
计算正多边形参数的公式对所有人来说都是通用的,因此我们重用了超类的 calculatePerimeter() 方法。
由于计算面积的公式对于不同的形状是不同的,所以我们在子类中创建了一个单独的方法来计算面积。