Swift 继承
在本教程中,我们将通过实例学习 Swift 继承及其类型。
与其他 OOP 语言一样,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
子类。
实例:继承
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()
这里,我们使用 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 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
类继承 Square
和 Pentagon
类。这些类中的每一个都有属性来存储边的长度和数量,因为它们对于所有多边形都是不同的。
class Square: RegularPolygon {
var length = 0
var sides = 0
}
我们将 length
和 sides
的值传递给 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
类,用于计算正多边形的周长。
这里,RegularSquare
和 RegularTriangle
继承自 RegularPolygon
。
计算正多边形参数的公式对所有人来说都是通用的,因此我们重用了超类的 calculatePerimeter()
方法。
由于计算面积的公式对于不同的形状是不同的,所以我们在子类中创建了一个单独的方法来计算面积。