11.继承

73 阅读7分钟

继承

目录

  1. 继承基础
  2. 内存结构
  3. 重写实例方法、下标
  4. 重写类型方法、下标
  5. 重写属性
  6. 属性观察器
  7. final关键字

继承基础

继承的基本概念

  • 值类型(枚举、结构体)不支持继承,只有支持继承
  • 没有父类的类,称为:基类
  • Swift并没有像OC、Java那样的规定:任何类最终都要继承自某个基类
  • 子类可以重写父类的下标、方法、属性,重写必须加上override关键字

基本语法

class Animal {
    var age = 0
    
    func speak() {
        print("Animal speak")
    }
}

class Dog: Animal {
    var weight = 0
    
    override func speak() {
        print("Dog speak")
    }
}

class ErHa: Dog {
    var iq = 0
    
    override func speak() {
        super.speak()
        print("ErHa speak")
    }
}

内存结构

继承层级的内存布局

class Animal {
    var age = 0
}

class Dog: Animal {
    var weight = 0
}

class ErHa: Dog {
    var iq = 0
}

内存分析

let a = Animal()
a.age = 10
print(Mems.size(ofRef: a))  // 32
/*
内存结构:
0x00000001000073e0  // 类型信息指针
0x0000000000000002  // 引用计数
0x000000000000000a  // age = 10
0x0000000000000000  // 内存对齐
*/
let d = Dog()
d.age = 10
d.weight = 20
print(Mems.size(ofRef: d))  // 32
/*
内存结构:
0x0000000100007490  // 类型信息指针
0x0000000000000002  // 引用计数
0x000000000000000a  // age = 10
0x0000000000000014  // weight = 20
*/
let e = ErHa()
e.age = 10
e.weight = 20
e.iq = 30
print(Mems.size(ofRef: e))  // 48
/*
内存结构:
0x0000000100007560  // 类型信息指针
0x0000000000000002  // 引用计数
0x000000000000000a  // age = 10
0x0000000000000014  // weight = 20
0x000000000000001e  // iq = 30
0x0000000000000000  // 内存对齐
*/

内存结构特点

  • 子类的内存布局包含父类的所有属性
  • 属性按照继承层级从上到下排列
  • 每个对象都有类型信息指针和引用计数
  • 内存大小会根据属性总数进行对齐

重写实例方法、下标

重写实例方法

class Animal {
    func speak() {
        print("Animal speak")
    }
    
    subscript(index: Int) -> Int {
        return index
    }
}

class Cat: Animal {
    override func speak() {
        super.speak()  // 调用父类方法
        print("Cat speak")
    }
    
    override subscript(index: Int) -> Int {
        return super[index] + 1  // 调用父类下标
    }
}

var anim: Animal
anim = Animal()
anim.speak()  // Animal speak
print(anim[6])  // 6

anim = Cat()
anim.speak()  // Animal speak
              // Cat speak
print(anim[6])  // 7

重写的特点

  • 使用override关键字标识重写
  • 可以使用super调用父类的实现
  • 重写方法的签名必须与父类完全一致
  • 支持多态:父类引用可以指向子类实例

重写类型方法、下标

class vs static

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

重写类型方法示例

class Animal {
    class func speak() {
        print("Animal speak")
    }
    
    class subscript(index: Int) -> Int {
        return index
    }
}

// 调用父类的类型方法
Animal.speak()      // Animal speak
print(Animal[6])    // 6

class Cat: Animal {
    override class func speak() {
        super.speak()
        print("Cat speak")
    }
    
    override class subscript(index: Int) -> Int {
        return super[index] + 1
    }
}

// 调用子类的类型方法
Cat.speak()         // Animal speak
                    // Cat speak
print(Cat[6])       // 7

static方法不能被重写

class Animal {
    static func staticMethod() {
        print("Animal static method")
    }
}

class Cat: Animal {
    // 编译错误:Cannot override static method
    // override static func staticMethod() { }
}

重写属性

重写属性的规则

  • 子类可以将父类的属性(存储、计算)重写为计算属性
  • 子类不可以将父类属性重写为存储属性
  • 只能重写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 = 6       // SubCircle setRadius
print(circle.diameter)  // SubCircle getDiameter
                        // Circle getDiameter
                        // SubCircle getRadius
                        // 12
circle.diameter = 20    // SubCircle setDiameter
                        // Circle setDiameter
                        // SubCircle setRadius
print(circle.radius)    // SubCircle getRadius
                        // 10

重写类型属性

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
        }
    }
}

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
        }
    }
}

Circle.radius = 6
print(Circle.diameter)      // Circle getDiameter
                           // 12
Circle.diameter = 20       // Circle setDiameter
print(Circle.radius)       // 10

SubCircle.radius = 6
print(SubCircle.diameter)  // SubCircle getDiameter
                          // Circle getDiameter
                          // 12
SubCircle.diameter = 20    // SubCircle setDiameter
                          // Circle setDiameter
print(SubCircle.radius)    // 10

属性观察器

为父类属性添加观察器

可以在子类中为父类属性(除了只读计算属性、let属性)增加属性观察器。

class Circle {
    var radius: Int = 1
}

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 1 10

父类已有观察器的情况

class Circle {
    var radius: Int = 1 {
        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 1 10
// SubCircle didSetRadius 1 10

为计算属性添加观察器

class Circle {
    var radius: Int {
        set {
            print("Circle setRadius", newValue)
        }
        get {
            print("Circle getRadius")
            return 20
        }
    }
}

class SubCircle: Circle {
    override var radius: Int {
        willSet {
            print("SubCircle willSetRadius", newValue)
        }
        didSet {
            print("SubCircle didSetRadius", oldValue, radius)
        }
    }
}

var circle = SubCircle()
circle.radius = 10
// Circle getRadius
// SubCircle willSetRadius 10
// Circle setRadius 10
// Circle getRadius
// SubCircle didSetRadius 20 20

类型属性观察器

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

final关键字

final的作用

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

final类

final class FinalClass {
    func method() {
        print("Final class method")
    }
}

// 编译错误:Cannot inherit from final class
// class SubClass: FinalClass { }

final方法

class Animal {
    final func finalMethod() {
        print("Animal final method")
    }
    
    func normalMethod() {
        print("Animal normal method")
    }
}

class Dog: Animal {
    // 编译错误:Cannot override final method
    // override func finalMethod() { }
    
    override func normalMethod() {
        print("Dog normal method")
    }
}

final属性

class Animal {
    final var finalProperty: Int = 0
    var normalProperty: Int = 0
}

class Dog: Animal {
    // 编译错误:Cannot override final property
    // override var finalProperty: Int { return 1 }
    
    override var normalProperty: Int {
        didSet {
            print("Dog property changed")
        }
    }
}

总结

继承的特点

  1. 单继承:Swift类只支持单继承
  2. 方法重写:使用override关键字
  3. 属性重写:只能重写为计算属性
  4. 类型安全:编译时检查重写的正确性
  5. 多态支持:父类引用可以指向子类实例

重写规则总结

重写目标是否支持注意事项
实例方法需要override关键字
类型方法(class)需要override关键字
类型方法(static)不能被重写
存储属性只能重写为计算属性
计算属性权限不能降低
下标实例和类型下标都支持

最佳实践

  1. 合理使用继承:遵循"is-a"关系
  2. 优先组合:考虑使用组合而非继承
  3. 谨慎使用final:限制扩展性,但提高性能
  4. 属性重写:通常用于添加验证逻辑
  5. 调用父类实现:使用super保持原有行为

性能考虑

  • 继承会增加方法调用的开销(虚函数表)
  • final关键字可以避免动态派发,提高性能
  • 过深的继承层级会影响内存布局和访问效率
  • 合理设计继承结构,避免不必要的复杂性