免费开源的iOS开发学习平台

Swift:14 继承

类可以从另外一个类中继承方法、属性、下标以及其他特性。当类继承自其他类时,继承的类叫子类,被继承的类叫超类。类可以覆盖超类的方法、属性和下标。

基类定义

在Swift中,不继承任何其他类的类,称之为基类。Swift中的类并不是从一个通用的基类继承而来的。下面示例定义一个基类,其中init是类的构造器,是一种特殊的类方法。

class Person{
    var name:String, age:Int
    init() {
        name = "person"
        age = 1
    }
    func toString() {
        print("name:\(name),age:\(age)",terminator:",")
    }
}

let p = Person()
p.toString() //打印:name:person,age:1

子类化

为了指明一个类有超类,将超类名写在子类名的后面,用冒号分隔即实现了子类化。如下演示继承自Person的Student子类。

class Student:Person{
    var studentId:Int
    convenience init(name:String,age:Int) {
        self.init()
        super.name = name
        super.age = age
    }
    override init() {
        studentId = 0
    }
    
    override func toString() {
        super.toString()
        print("studentId:\(studentId)")
    }
}

let student = Student(name: "Liming", age: 18)
student.studentId = 100

student.toString() //打印:name:Liming,age:20,studentId:100

覆盖

子类可以对继承来的实例方法、类方法、实例属性或下标进行覆盖实现。为了覆盖某个特性,需要在覆盖定义的特性前面加上override关键词。通过super来访问父类中的同名方法或者属性。
可以提供自定义的getter(或setter)来覆盖任意继承来的属性,无论它是存储属性还是计算属性。子类并不知道继承来的属性是存储属性还是计算属性,只知道继承来的属性会有一个特定的名称和类型。在覆盖一个属性时,必须将它的名称和类型都写出来。这样才能让编译器检查覆盖的属性是与超类中同名同类型的属性是否匹配。
可以通过为子类继承来的属性提供getter和setter,将一个只读属性覆盖为一个可读写的属性。但是,不可以将一个继承来的可读写的属性覆盖为一个只读属性。

class Student:Person{
    var studentId:Int
    convenience init(name:String,age:Int) {
        self.init()
        super.name = name
        super.age = age
    }
    override init() {
        studentId = 0
    }
    
    override var age: Int{
        get{
            return super.age
        }
        set{
            super.age = max(8,newValue)
        }
    }
    
    override func toString() {
        super.toString()
        print("studentId:\(studentId)")
    }
}

let student = Student(name: "Liming", age: 18)
student.studentId = 100
student.toString() //打印结果:name:Liming,age:18,studentId:100

student.age = 6
student.toString() //打印结果:name:Liming,age:8,studentId:100

防止覆盖

可以通过将方法,属性或下标脚本标记为final来防止它们被覆盖,只需要在声明关键词前加上final关键词即可。
任何覆盖final方法,属性或下标的尝试都会导致编译时的报错。在扩展中,添加到类里的方法,属性或下标也可以在扩展的定义里标记为final。
可以通过在关键词class前添加final关键词(final class)来将整个类标记为final。所有对这种类进行继承的尝试都会导致编译时报错。

class Person{
    var name:String, age:Int
    init() {
        name = "person"
        age = 1
    }
    func toString() {
        print("name:\(name),age:\(age)",terminator:",")
    }
    
    final func addAge(add:Int){
        age += add
    }
}

class Teacher:Person{
    /*//报错,final方法无法被覆盖
    override func addAge(add:Int){
        
    }
    */
    override func toString() {
        super.toString()
        print("teacher")
    }
}
let teacher = Teacher()
teacher.addAge(add: 10)
teacher.toString()     //打印:name:person,age:11,teacher

示例代码

https://github.com/99ios/23.15