Swift: Swift 继承与多态:面向对象编程核心概念

继承是面向对象编程的三大特性之一,允许一个类基于另一个类构建,复用和扩展已有行为。本课深入 Swift 的继承机制与多态的应用。

1. 你将学到


2. 一个 UI 开发者的真实故事

(1) 痛点:UI 组件大量重复代码

Charlie 开发 UI 组件库,需要 Button、Label、TextField 等组件,它们都有相似的基础行为:

SWIFT
class Button {
    var frame: CGRect
    var backgroundColor: UIColor
    func render() { /* 绘制背景 */ }
    func handleTap() { /* 处理点击 */ }
}
class Label {
    var frame: CGRect
    var backgroundColor: UIColor
    func render() { /* 绘制背景 */ }
}

Button 和 Label 中的 framebackgroundColorrender() 几乎一样。每次新增组件都复制粘贴相同的属性,修改基础行为要改 10 个文件。

(2) 继承的解法

SWIFT
class UIView {
    var frame: CGRect
    var backgroundColor: UIColor
    func render() { /* 绘制基础背景 */ }
}
class Button: UIView {
    override func render() {
        super.render()          // 先画背景
        // 再画按钮特有的样式
    }
    func handleTap() { }
}
class Label: UIView {
    override func render() {
        super.render()
        // 再画标签特有的样式
    }
}

公共属性定义一次,所有子类复用。修改基础行为只需改一个文件。

(3) 收益:复用 + 可扩展

维度 复制粘贴式 继承式
代码复用 0%——每个组件独立 100%——基础属性和方法
修改成本 改 10 个文件 改 1 个父类
新增组件 复制整个文件 继承 + 添加差异
一致性 容易遗漏修改 父类保证行为一致
可扩展性 重写风险高 override + super 可控

3. 继承的基础

(1) 子类化

100%
graph TB
    A[Animal] --> B["属性: name, age"]
    A --> C["方法: makeSound()"]
    B --> D[Dog]
    C --> D
    D --> E["属性: breed"]
    D --> F["重写: makeSound()"]
    A --> G[Cat]
    G --> H["属性: color"]
    G --> I["重写: makeSound()"]
概念 说明
基类/父类 被继承的类,Swift 中所有类都继承自 AnyObject
子类 继承父类的类,可以添加新属性和方法
单继承 Swift 只支持单继承(一个子类只有一个父类)
根类 没有父类的类称为根类

▶ 示例:基本继承

SWIFT
// ============================================
// 继承的基本用法
// ============================================
// 基类
class Vehicle {
    var make: String
    var model: String
    var year: Int
    init(make: String, model: String, year: Int) {
        self.make = make
        self.model = model
        self.year = year
    }
    func description() -> String {
        return "\(year) \(make) \(model)"
    }
    func startEngine() {
        print("Engine started")
    }
}
// 子类——继承 Vehicle
class Car: Vehicle {
    var numberOfDoors: Int
    init(make: String, model: String, year: Int, numberOfDoors: Int) {
        self.numberOfDoors = numberOfDoors
        super.init(make: make, model: model, year: year)  // 调用父类初始化器
    }
    func honk() {
        print("Beep beep!")
    }
}
// 子类——继承 Vehicle
class Motorcycle: Vehicle {
    var hasSidecar: Bool
    init(make: String, model: String, year: Int, hasSidecar: Bool = false) {
        self.hasSidecar = hasSidecar
        super.init(make: make, model: model, year: year)
    }
    func wheelie() {
        print("Doing a wheelie!")
    }
}
let car = Car(make: "Toyota", model: "Camry", year: 2022, numberOfDoors: 4)
print(car.description())  // 继承的方法
car.honk()                // Car 自己的方法

输出:

TEXT 📖 仅展示
2022 Toyota Camry
Beep beep!

4. 重写与 super

(1) override 重写

子类可以用 override 重写父类的方法、计算属性或下标:

可重写的内容 override 要求 说明
实例方法 ✅ 必须加 提供新的函数体
计算属性 ✅ 必须加 提供新的 getter/setter
下标 ✅ 必须加 提供新的下标实现
存储属性 ❌ 不能 存储属性不能重写

▶ 示例:重写方法

SWIFT
// ============================================
// override 重写父类方法
// ============================================
class Animal {
    var name: String
    init(name: String) { self.name = name }
    func makeSound() {
        print("\(name) makes a sound")
    }
}
class Dog: Animal {
    override func makeSound() {
        print("\(name) barks: Woof!")
    }
}
class Cat: Animal {
    override func makeSound() {
        print("\(name) meows: Meow!")
    }
}
let dog = Dog(name: "Buddy")
let cat = Cat(name: "Whiskers")
dog.makeSound()
cat.makeSound()

输出:

TEXT 📖 仅展示
Buddy barks: Woof!
Whiskers meows: Meow!

(2) super 调用父类

在重写中通过 super 调用父类版本:

SWIFT
// ============================================
// super 关键字调用父类
// ============================================
class Shape {
    var color: String
    init(color: String) {
        self.color = color
        print("Shape init: \(color)")
    }
    func draw() {
        print("Drawing a shape in \(color)")
    }
}
class Circle: Shape {
    var radius: Double
    init(color: String, radius: Double) {
        self.radius = radius
        super.init(color: color)  // 先完成自己的初始化,再调父类
    }
    override func draw() {
        super.draw()  // 先执行父类的绘制
        print("  It's a circle with radius \(radius)")
    }
}
let circle = Circle(color: "Red", radius: 5.0)
circle.draw()

输出:

TEXT 📖 仅展示
Shape init: Red
Drawing a shape in Red
  It's a circle with radius 5

💡 提示: 初始化时,子类必须先完成自己的存储属性赋值,再调用 super.init。这是 Swift 的两阶段初始化安全机制。


5. final 与多态

(1) final 阻止继承

final 关键字可以阻止类被继承,或阻止方法/属性被重写:

用法 效果
final class 该类不能被继承
final func 该方法不能被重写
final var 该属性不能被重写

▶ 示例:final 的使用

SWIFT
// ============================================
// final 阻止继承和重写
// ============================================
class Calculator {
    // 基础运算可重写
    func add(_ a: Int, _ b: Int) -> Int { return a + b }
    // 核心逻辑不允许重写
    final func process(_ a: Int, _ b: Int, operation: String) -> String {
        let result: Int
        switch operation {
        case "add": result = add(a, b)
        default: result = 0
        }
        return "Result: \(result)"
    }
}
// 这个子类可以 override add,但不能 override process
class AdvancedCalculator: Calculator {
    override func add(_ a: Int, _ b: Int) -> Int {
        print("Advanced add: \(a) + \(b)")
        return a + b
    }
    // override func process(...)  // 编译错误!
}
let calc = AdvancedCalculator()
print(calc.process(3, 4, operation: "add"))

输出:

TEXT 📖 仅展示
Advanced add: 3 + 4
Result: 7

(2) 多态

多态允许用父类类型的变量引用子类实例,调用时执行子类的重写实现:

100%
graph TB
    A["let shapes: [Shape] = [Circle(), Rectangle()]"] --> B["for shape in shapes"]
    B --> C["shape.draw()  ← 多态"]
    C --> D["Circle 的 draw()"]
    C --> E["Rectangle 的 draw()"]

▶ 示例:多态的实际应用

SWIFT
// ============================================
// 多态——统一处理不同类型的对象
// ============================================
class Employee {
    let name: String
    init(name: String) { self.name = name }
    func work() -> String {
        return "\(name) is working"
    }
    func bonus() -> Double {
        return 0
    }
}
class Developer: Employee {
    override func work() -> String { return "\(name) is writing code" }
    override func bonus() -> Double { return 5000 }
}
class Designer: Employee {
    override func work() -> String { return "\(name) is designing UI" }
    override func bonus() -> Double { return 3000 }
}
class Manager: Employee {
    override func work() -> String { return "\(name) is managing team" }
    override func bonus() -> Double { return 8000 }
}
// 多态:统一处理不同子类
let team: [Employee] = [
    Developer(name: "Alice"),
    Designer(name: "Bob"),
    Manager(name: "Charlie")
]
var totalBonus = 0.0
for member in team {
    print(member.work())   // 动态调用各自的实现
    totalBonus += member.bonus()
}
print("Total bonus: $\(totalBonus)")

输出:

TEXT 📖 仅展示
Alice is writing code
Bob is designing UI
Charlie is managing team
Total bonus: $16000.0

6. 完整示例:UI 组件渲染系统

SWIFT
// ============================================
// 完整示例:UI 组件渲染系统
// 功能:继承 + 重写 + super + final + 多态综合
// ============================================
import Foundation
// 1. 基类(可继承)
class UIComponent {
    let id: String
    var x: Int
    var y: Int
    init(id: String, x: Int, y: Int) {
        self.id = id
        self.x = x
        self.y = y
    }
    func render() -> String {
        return "[\(id)] at (\(x), \(y))"
    }
    // 核心逻辑——禁止重写
    final func display() {
        print(render())
    }
}
// 2. 按钮子类
class Button: UIComponent {
    let label: String
    init(id: String, x: Int, y: Int, label: String) {
        self.label = label
        super.init(id: id, x: x, y: y)
    }
    override func render() -> String {
        let base = super.render()
        return "\(base) [Button: \(label)]"
    }
}
// 3. 文本框子类
class TextField: UIComponent {
    var text: String
    init(id: String, x: Int, y: Int, text: String = "") {
        self.text = text
        super.init(id: id, x: x, y: y)
    }
    override func render() -> String {
        return "\(super.render()) [TextField: \"\(text)\"]"
    }
}
// 4. 多态渲染
let components: [UIComponent] = [
    Button(id: "btn1", x: 10, y: 20, label: "Submit"),
    TextField(id: "txt1", x: 10, y: 60, text: "Hello"),
    Button(id: "btn2", x: 10, y: 100, label: "Cancel"),
    TextField(id: "txt2", x: 10, y: 140)
]
for component in components {
    component.display()  // 多态调用
}

输出:

TEXT 📖 仅展示
[btn1] at (10, 20) [Button: Submit]
[txt1] at (10, 60) [TextField: "Hello"]
[btn2] at (10, 100) [Button: Cancel]
[txt2] at (10, 140) [TextField: ""]

❓ 常见问题

Q Swift 支持多继承吗?
A 不支持。Swift 是单继承语言(一个子类只能有一个父类)。多继承的需求通过协议(Protocol)实现,一个类可以遵守多个协议。
Q 为什么有时重写方法时必须调 super?
A 不是必须的,但如果不调 super,父类中的逻辑就完全被替换了。通常做法是在子类中先调 super 执行公共逻辑,再补充子类特有的行为。是否调 super 取决于设计意图。
Q final class 和 struct 在不可继承上一样吗?
A 表现上一样——都不能被继承。但 struct 是值类型,class 是引用类型。用 final class 在保持引用类型特性的同时阻止继承。如果既不需要继承也不需要引用语义,就用 struct。
Q 向上转型(upcasting)和向下转型有什么区别?
A 向上转型是将子类对象当作父类类型使用(自动隐式,如 Employee e = Developer(...))。向下转型是将父类引用转回子类类型(需用 as?as!),转换可能失败所以必须是可选类型。
Q 初始化时为什么必须先初始化自己的存储属性再调 super.init?
A 这是 Swift 两阶段初始化安全机制。阶段 1:从子类到父类逐层初始化存储属性。阶段 2:从父类到子类逐层自定义。确保在调父类 init 前所有存储属性有确定值,避免未初始化状态被父类方法访问。

📖 小节


📝 作业

  1. 基础题: 创建一个 Person 基类(属性:nameage,方法:introduce()),再创建 StudentTeacher 子类,分别重写 introduce() 方法并添加各自的属性(studentIdsubject)。
  2. 进阶题: 设计一个 MediaItem 基类,包含 title 属性和 play() 方法。创建 Movie(额外:director)和 Song(额外:artist)子类重写 play()。用多态数组统一播放。
  3. 挑战题: 实现一个「权限控制系统」:基类 UserpermissionLevel 属性和 canAccess(_:) 方法。创建 AdminUserEditorUserViewerUser 子类,AdminUser 使用 final 方法 override func canAccess(_:) 始终返回 true。使用多态数组统一检查不同用户的访问权限。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏