Swift 继承

Swift 中的继承(Inheritance)是面向对象编程的核心特性之一,仅类(class)支持继承,结构体和枚举不支持。继承允许子类复用、扩展或重写父类的属性、方法、下标等。


一、基本语法

class 父类 {
    // 属性、方法、下标...
}

class 子类: 父类 {
    // 可重写父类成员
}

二、核心示例:动物与狗

class Animal {
    var name: String
    var legs: Int

    init(name: String, legs: Int) {
        self.name = name
        self.legs = legs
    }

    func speak() {
        print("动物发出声音")
    }

    func description() -> String {
        return "\(name) 有 \(legs) 条腿"
    }
}

class Dog: Animal {
    var breed: String

    // 指定初始化器必须先初始化自身属性,再调用 super.init
    init(name: String, breed: String) {
        self.breed = breed
        super.init(name: name, legs: 4)
    }

    // 重写方法
    override func speak() {
        print("汪汪!我是 \(name)")
    }

    // 重写属性(计算属性)
    override var description: String {
        return super.description + ",品种:\(breed)"
    }
}

let dog = Dog(name: "旺财", breed: "拉布拉多")
dog.speak()                 // 汪汪!我是 旺财
print(dog.description())    // 旺财 有 4 条腿,品种:拉布拉多

三、继承的关键规则

规则说明
仅类支持继承structenum 不能继承
单继承一个类只能继承一个父类
初始化器继承子类必须正确调用 super.init
重写override 标记
防止重写final 修饰

四、初始化器继承规则(两阶段初始化)

1. 指定初始化器(Designated Initializer)

class Person {
    var name: String
    init(name: String) { self.name = name }  // 指定
}

class Student: Person {
    var studentID: String
    init(name: String, studentID: String) {
        self.studentID = studentID
        super.init(name: name)  // 必须调用父类指定初始化器
    }
}

2. 便利初始化器(Convenience Initializer)

class Person {
    var name: String
    init(name: String) { self.name = name }

    convenience init() {
        self.init(name: "匿名")
    }
}

class Student: Person {
    var studentID: String

    init(name: String, studentID: String) {
        self.studentID = studentID
        super.init(name: name)
    }

    // 便利初始化器必须调用本类的指定初始化器
    convenience init(studentID: String) {
        self.init(name: "学生", studentID: studentID)
    }
}

五、重写(Override)

1. 重写方法

override func speak() { ... }

2. 重写属性(计算属性或观察器)

class Vehicle {
    var speed: Double = 0
}

class Car: Vehicle {
    override var speed: Double {
        get { super.speed }
        set { super.speed = min(newValue, 200) }  // 限速
    }
}

3. 重写下标

class Base {
    subscript(index: Int) -> Int {
        return index
    }
}

class Derived: Base {
    override subscript(index: Int) -> Int {
        return index * 2
    }
}

六、final 防止继承与重写

final class ImmutablePoint {
    let x: Double, y: Double
    init(x: Double, y: Double) {
        self.x = x
        self.y = y
    }
}
// 不能被继承

class Shape {
    final func area() -> Double { 0 }
}
// 不能被重写

七、类型转换(Type Casting)

1. is 检查类型

let animals: [Animal] = [Dog(name: "小黑", breed: "土狗"), Animal(name: "鸟", legs: 2)]

for animal in animals {
    if animal is Dog {
        print("\(animal.name) 是狗")
    }
}

2. as? / as! 转换

for animal in animals {
    if let dog = animal as? Dog {
        print("狗狗品种:\(dog.breed)")
    }
}

3. AnyAnyObject

let objects: [Any] = [1, "hello", Dog(name: "Tom", breed: "金毛")]

for obj in objects {
    switch obj {
    case let dog as Dog:
        dog.speak()
    case let str as String:
        print("字符串: \(str)")
    default:
        break
    }
}

八、继承 vs 组合(Composition)

继承组合
是“is-a”关系是“has-a”关系
强耦合松耦合
易滥用更灵活

推荐组合优于继承(Favor composition over inheritance)

// 组合:更好
protocol Engine {
    func start()
}

class Car {
    let engine: Engine
    init(engine: Engine) { self.engine = engine }
}

// 继承:慎用
class ElectricCar: Car { ... }

九、继承链中的 deinit

class File {
    deinit { print("文件关闭") }
}

class Document: File {
    deinit { print("文档释放") }
}

var doc: Document? = Document()
doc = nil
// 文档释放
// 文件关闭

十、继承与协议结合(推荐)

protocol Flyable {
    func fly()
}

class Bird: Animal, Flyable {
    func fly() { print("\(name) 在飞") }
}

协议 + 继承 = 灵活设计


最佳实践总结

场景推荐
共享代码继承(谨慎)
多态继承 + override
防止修改final
灵活扩展协议 + 组合
模型层struct + 协议(无继承)
UI 控制器class + 继承(如 UIViewController

常见面试题

  1. 结构体能继承吗?
    → 不能。仅 class 支持。
  2. 子类初始化器必须调用 super.init 吗?
    → 是的(指定初始化器必须)。
  3. 如何防止某个方法被重写?
    final func
  4. override 忘记写会怎样?
    → 编译错误(如果父类有同名方法)
  5. 继承和协议哪个更推荐?
    协议优先,继承仅在必要时使用。

小技巧

// 1. 自动继承初始化器(当子类无新属性)
class A {
    var x: Int
    init(x: Int) { self.x = x }
}

class B: A {}  // 自动继承 init(x:)

// 2. 使用 where 限制类型转换
for case let dog as Dog in animals where dog.breed == "金毛" {
    print(dog.name)
}

// 3. 父类引用子类对象(多态)
let animal: Animal = Dog(name: "Jerry", breed: "柯基")
animal.speak()  // 汪汪!我是 Jerry(动态派发)

高级话题(可继续提问)

  • 方法派发机制(vtable、witness table)
  • 类簇(Class Cluster)设计模式
  • 继承与 ARC 内存管理
  • SwiftUI 中 @Observable 类与继承
  • 协议导向编程(POP)替代继承

需要完整项目示例(如 MVC 继承结构)、性能分析,或与协议组合实战?欢迎继续提问!

文章已创建 2481

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部