問題1:什么是多態(tài)?
指允許不同類的對(duì)象對(duì)同一消息做出響應(yīng)。即同一消息可以根據(jù)發(fā)送對(duì)象的不同而采用多種不同的行為方式。(發(fā)送消息就是函數(shù)調(diào)用)實(shí)現(xiàn)多態(tài)的技術(shù)稱為:動(dòng)態(tài)綁定(dynamic binding),是指在執(zhí)行期間判斷所引用對(duì)象的實(shí)際類型,根據(jù)其實(shí)際的類型調(diào)用其相應(yīng)的方法。
問題2:swift 是怎樣表示多態(tài)的?
子類重寫父類的方法,使用父類聲明的變量分別創(chuàng)建子類和父類的對(duì)象,并使用變量調(diào)用相同的函數(shù)。
//基類
class Animal {
func speak() {
print("Animal - Speak")
}
func see() {
print("Animal - see")
}
func sleep() {
print("Animal - sleep")
}
}
//子類繼承父類
class Dog: Animal {
//重寫父類的speak,see函數(shù)
override func speak() {
print("Dog - Speak")
}
override func see() {
print("Dog - see")
}
func run(){
print("Dog - run")
}
}
//定義一個(gè)變量
var animal: Animal
//創(chuàng)建Animal的對(duì)象,賦值給animal
animal = Animal()
//基類調(diào)用seapk,see,sleep函數(shù)
animal.speak()
animal.see()
animal.sleep()
//創(chuàng)建Dog的對(duì)象,也賦值給animal
animal = Dog()
//子類也調(diào)用seapk,see,sleep函數(shù)
animal.speak()
animal.see()
animal.sleep()
打印結(jié)果
Animal - Speak
Animal - see
Animal - sleep
Dog - Speak
Dog - see
Animal - sleep
根據(jù)對(duì)象不同,執(zhí)行不同的函數(shù)。
問題3:swfit底層是怎么通過對(duì)象調(diào)用函數(shù)的?
使用xcode查看匯編代碼,調(diào)用speak函數(shù)主要匯編代碼如下:

分析:
1.找到關(guān)鍵性匯編指令callq 調(diào)用函數(shù)。*0x50(%rcx),指將rcx的值加上0x50以后取出8個(gè)字節(jié)的內(nèi)容。rcx存儲(chǔ)的是類型信息,根據(jù)類型信息偏移x50找到函數(shù)speak并調(diào)用。
2.取出寄存器%rax里面存儲(chǔ)8個(gè)字節(jié)賦值給寄存器%rcx。獲取寄存器rax前八個(gè)字節(jié)的地址值并取出改地址值存儲(chǔ)的內(nèi)容,賦值給rcx。這時(shí)的rcx存儲(chǔ)的是Animal的類型信息。
3.將0x23cc(%rip)里面內(nèi)存的8個(gè)字節(jié)給寄存器%rcx,這里看注釋,0x23cc(%rip)就應(yīng)該為變量animal,找到animal變量取出變量存儲(chǔ)的堆空間地址賦值給寄存器%rax。



總結(jié):
通過指針變量尋找對(duì)象的堆空間,在根據(jù)堆空間的前8個(gè)字節(jié)存儲(chǔ)的指針查找類型信息的內(nèi)存地址,從類型信息偏移獲取對(duì)象的函數(shù)地址值并進(jìn)行調(diào)用。
多態(tài)的實(shí)現(xiàn)是根據(jù)對(duì)象的堆空間查找前8個(gè)字節(jié)的類型信息,不同類的類型信息是不相同的,每個(gè)函數(shù)都一個(gè)函數(shù)地址,這個(gè)函數(shù)地址在編譯的時(shí)候就確認(rèn)并存儲(chǔ)到類型信息里面。過程就是指針->堆空間->類型信息->地址偏移。