多態:父類指針指向子類對象
多態的實現原理:
OC: Runtime
C++: 虛表(虛函數表)
Swift:類似於虛表
多態代碼:
class Animal {
func speak() {
print("Animal speak")
}
func eat() {
print("Animal eat")
}
func sleep() {
print("Animal sleep")
}
}
class Dog: Animal {
override func speak() {
print("Dog speak")
}
override func eat() {
print("Dog eat")
}
}
var anim: Animal
anim = Animal()
anim.speak()
anim.eat()
anim.sleep()
anim = Dog()
anim.speak()
anim.eat()
anim.sleep()
輸出結果:
對比結構體和類對方法的調用
- 結構體代碼:
struct Animal {
func speak() {
print("Animal speak")
}
func eat() {
print("Animal eat")
}
func sleep() {
print("Animal sleep")
}
}
var anim = Animal()
anim.speak()
anim.eat()
anim.sleep()
結構體的反彙編代碼:
由上圖可以看出,結構體的函數的地址在調用時一開始就固定的也就是一編譯完就能確定調用哪個函數,這是因爲結構體不存在繼承,可以直接確定
- 類代碼:
class Animal {
func speak() {
print("Animal speak")
}
func eat() {
print("Animal eat")
}
func sleep() {
print("Animal sleep")
}
}
var anim = Animal()
anim.speak()
anim.eat()
anim.sleep()
類的反彙編代碼:
上圖以此爲speak,eat,sleep方法的反彙編代碼,我們可以看出,它們的地址是不固定的,這是因爲類存在繼承特性,需要運行時才能確定真正調用哪個方法
多態實現原理
- 多態代碼
class Animal {
func speak() {
print("Animal speak")
}
func eat() {
print("Animal eat")
}
func sleep() {
print("Animal sleep")
}
}
class Dog: Animal {
override func speak() {
print("Dog speak")
}
override func eat() {
print("Dog eat")
}
func run() {
print("Dog run")
}
}
var anim = Animal()
anim.speak()
anim.eat()
anim.sleep()
anim = Dog()
anim.speak()
anim.eat()
anim.sleep()
- 多態部分反彙編代碼
1中是從全局變量anim的取出8個字節給rax,rax裏也就是堆空間Dog對象的地址值
2中是從堆空間裏取出8個字節給rcx,rcx裏存儲的就是Dog對象堆空間內存的前八個字節,也就是類型信息(存儲着類的相關信息,包括裏面的方法等)。
3就是找到存儲類型信息的內存地址,加上方法的偏移量,就可以找到對應要調用的方法
圖解:
注意:兩個不同的Dog對象前8個字節相同,因爲它存儲着共同的一樣的類型信息,而且類型信息存儲在全局區