继承
目录
继承基础
继承的基本概念
- 值类型(枚举、结构体)不支持继承,只有类支持继承
- 没有父类的类,称为:基类
- 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")
}
}
}
总结
继承的特点
- 单继承:Swift类只支持单继承
- 方法重写:使用
override关键字 - 属性重写:只能重写为计算属性
- 类型安全:编译时检查重写的正确性
- 多态支持:父类引用可以指向子类实例
重写规则总结
| 重写目标 | 是否支持 | 注意事项 |
|---|---|---|
| 实例方法 | ✅ | 需要override关键字 |
| 类型方法(class) | ✅ | 需要override关键字 |
| 类型方法(static) | ❌ | 不能被重写 |
| 存储属性 | ✅ | 只能重写为计算属性 |
| 计算属性 | ✅ | 权限不能降低 |
| 下标 | ✅ | 实例和类型下标都支持 |
最佳实践
- 合理使用继承:遵循"is-a"关系
- 优先组合:考虑使用组合而非继承
- 谨慎使用final:限制扩展性,但提高性能
- 属性重写:通常用于添加验证逻辑
- 调用父类实现:使用
super保持原有行为
性能考虑
- 继承会增加方法调用的开销(虚函数表)
final关键字可以避免动态派发,提高性能- 过深的继承层级会影响内存布局和访问效率
- 合理设计继承结构,避免不必要的复杂性