您的位置:首页 > 移动开发 > Swift

Swift系列十二 - 继承

2021-04-28 09:48 891 查看

继承是面向对象语言的三大特性之一。

一、继承特性

  • 值类型(枚举、结构体)不支持继承,只有类支持继承。

  • 没有父类的类,称为基类

    Swift并没有像OC、Java那样的规定:任何类最终都要继承自某个基类
  • 子类可以重写父类的下标、方法、属性,重写必须加上

    override
    关键字

  • 二、内存结构

    示例代码:

    class Animal {
    var age = 0
    }
    let a = Animal()
    a.age = 10
    print(Mems.size(ofRef: a)) // 输出:32
    print(Mems.memStr(ofRef: a))
    /*
    输出:
    0x000000010000c478
    0x0000000000000002
    0x000000000000000a
    0x00027fff84bb8630
    */

    如果定义一个继承

    Animal
    的类,内存有什么变化呢?

    class Dog: Animal {
    var weight = 0
    }
    let d = Dog()
    d.age = 10
    d.weight = 20
    print(Mems.size(ofRef: d)) // 输出:32
    print(Mems.memStr(ofRef: d))
    /*
    输出:
    0x000000010000c528
    0x0000000000000002
    0x000000000000000a
    0x0000000000000014
    */
    
    // 上面的代码等价于下面的代码
    class Dog {
    var age = 0
    var weight = 0
    }

    一般从父类继承过来的成员内存放在前面,自己的成员内存放在后面。

    三、重写

    3.1. 重写实例方法、下标

    基类示例代码:

    class Animal {
    func<
    20000
    /span> eat() {
    print("Animal eat")
    }
    subscript(index: Int) -> Int { index }
    }
    var animal: Animal
    animal = Animal()
    animal.eat()
    print(animal[0])
    /*
    输出:
    Animal eat
    0
    */

    继承重写示例代码:

    class Dog: Animal {
    override func eat() {
    super.eat()
    print("Dog eat")
    }
    override subscript(index: Int) -> Int {
    index + 1
    }
    }
    animal = Dog()
    animal.eat()
    print(animal[0])
    /*
    输出:
    Animal eat
    Dog eat
    1
    */

    分析:

    animal = Dog()
    父类指针指向子类对象,体现了多态。重写父类方法使用关键字
    override
    ,如果需要执行父类的行为,使用
    super

    3.2. 重写类型方法、下标

    • class
      修饰的类型方法、下标,允许被子类重写
    • static
      修饰的类型方法、下标,不允许被子类重写

    示例代码:

    class Animal {
    class func eat() {
    print("Animal eat")
    }
    class subscript(index: Int) -> Int { index }
    }
    Animal.eat()
    print(Animal[0])
    /*
    输出:
    Animal eat
    0
    */
    
    class Dog: Animal {
    override class func eat() {
    super.eat()
    print("Dog eat")
    }
    override class subscript(index: Int) -> Int {
    super[index] + 1
    }
    }
    Dog.eat()
    print(Dog[0])
    /*
    输出:
    Animal eat
    Dog eat
    1
    */

    如果子类和父类都使用

    static
    修饰,直接报错:

    如果父类用

    class
    修饰,子类用
    static
    修饰,是可以正常运行的:

    3.3. 重写属性

    3.3.1 重写实例属性

    • 子类可以将父类的属性(存储、计算)重写为计算属性

    • 子类不可以将父类属性重写为存储属性

    • 只能重写

      var
      属性,不能重写
      let
      属性

    • 重写时,属性名、类型要一致

    • 子类重写后的属性权限【不能小于】父类属性的权限

      如果父类属性是只读的,那么子类重写后的属性可以是只读的,也可以是可读写的
    • 如果父类属性是可读写的,那么子类重写后的属性也必须是可读写的

    示例代码:

    class Circle {
    var radius: Int = 0
    var diameter: Int {
    set {
    print("Circle setDiameter")
    radius = newValue / 2
    }
    get {
    print("Circle getDiameter")
    return radius * 2
    }
    }
    }
    var circle: Circle
    circle = Circle()
    circle.radius = 6
    print(circle.diameter)
    /*
    输出:
    Circle getDiameter
    12
    */
    circle.diameter = 20
    // 输出:Circle setDiameter
    print(circle.radius)
    // 输出:10

    子类继承示例代码:

    class SubCircle: Circle {
    override var radius: Int {
    set {
    print("SubCircle setRadius")
    super.radius = newValue > 0 ? newValue : 0
    }
    get {
    print("SubCircle getRadius")
    return super.radius
    }
    }
    override var diameter: Int {
    set {
    print("SubCircle setDiameter")
    super.diameter = newValue > 0 ? newValue : 0
    }
    get {
    print("SubCircle getDiameter")
    return super.diameter
    }
    }
    }
    circle = SubCircle()
    circle.radius = 12
    // 输出:SubCircle setRadius
    
    print(circle.diameter)
    /*
    输出:
    SubCircle getDiameter
    Circle getDiameter
    SubCircle getRadius
    24
    */
    
    circle.diameter = 30
    /*
    输出:
    SubCircle setDiameter
    Circle setDiameter
    SubCircle setRadius
    */
    
    print(circle.radius)
    /*
    输出:
    SubCircle getRadius
    15
    */

    分析:子类调用父类时,本质还是子类在调用,所以父类中的属性

    set
    方法会在子类中查找。

    3.3.2 重写类型属性

    • class
      修饰的计算类型属性,可以被子类重写
    • static
      修饰的类型属性(存储、计算),不可以被子类重写

    示例代码:

    class Circle {
    static var radius: Int = 0
    class var diameter: Int {
    set {
    print("Circle setDiameter")
    radius = newValue / 2
    }
    get {
    print("Circle getDiameter")
    return radius * 2
    }
    }
    }
    Circle.radius = 6
    print(Circle.diameter)
    /*
    输出:
    Circle getDiameter
    12
    */
    
    class SubCircle: Circle {
    override static var diameter: Int {
    set {
    print("SubCircle setDiameter")
    super.diameter = newValue > 0 ? newValue : 0
    }
    get {
    print("SubCircle getDiameter")
    return super.diameter
    }
    }
    }
    print(SubCircle.diameter)
    /*
    输出:
    SubCircle getDiameter
    Circle getDiameter
    12
    */
    
    print(SubCircle.radius)
    // 输出:6

    3.4 属性观察器

    可以在子类中为父类属性(除了只读计算属性、

    let
    属性)增加属性观察器。

    示例代码:

    class Circle {
    var radius: Int = 0
    }
    
    class SubCircle: Circle {
    override var radius: Int {
    willSet {
    print("SubCircle willSetRadius", newValue)
    }
    didSet {
    print("SubCircle didSetRadius", oldValue, radius)
    }
    }
    }
    var circle = SubCircle()
    circle.radius = 10
    /*
    输出:
    SubCircle willSetRadius 10
    SubCircle didSetRadius 0 10
    */

    如果父类属性已经添加了属性观察器,子类同样也可以为父类属性添加观察器:

    class Circle {
    var radius: Int = 0 {
    willSet {
    print("Circle willSetRadius", newValue)
    }
    didSet {
    print("Circle didSetRadius", oldValue, radius)
    }
    }
    }
    
    class SubCircle: Circle {
    override var radius: Int {
    willSet {
    print("SubCircle willSetRadius", newValue)
    }
    didSet {
    print("SubCircle didSetRadius", oldValue, radius)
    }
    }
    }
    var circle = SubCircle()
    circle.radius = 10
    /*
    输出:
    SubCircle willSetRadius 10
    Circle willSetRadius 10
    Circle didSetRadius 0 10
    SubCircle didSetRadius 0 10
    */

    子类可以为父类计算属性添加属性观察器:

    class Circle {
    class var radius: Int {
    set {
    print("Circle setRadius", newValue)
    }
    get {
    print("Circle getRadius")
    return 20
    }
    }
    }
    
    class SubCircle: Circle {
    override static var radius: Int {
    willSet {
    print("SubCircle willSetRadius", newValue)
    }
    didSet {
    print("SubCircle didSetRadius", oldValue, radius)
    }
    }
    }
    SubCircle.radius = 10
    /*
    输出:
    Circle getRadius
    SubCircle willSetRadius 10
    Circle setRadius 10
    Circle getRadius
    SubCircle didSetRadius 20 20
    */

    为什么首次会输出

    Circle getRadius

    其实
    Circle getRadius
    获取的就是
    oldValue
    ,因为只有拿到之前的值,才能设置观察新值的变化。

    3.5 final

    • final
      修饰的方法、下标、属性,禁止被重写;
    • final
      修饰的类,禁止被继承。

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: