Swift-多态的底层实现
2020-02-28 本文已影响0人
z_z
问题1:什么是多态?
指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
问题2:swift 是怎样表示多态的?
子类重写父类的方法,使用父类声明的变量分别创建子类和父类的对象,并使用变量调用相同的函数。
//基类
class Animal {
func speak() {
print("Animal - Speak")
}
func see() {
print("Animal - see")
}
func sleep() {
print("Animal - sleep")
}
}
//子类继承父类
class Dog: Animal {
//重写父类的speak,see函数
override func speak() {
print("Dog - Speak")
}
override func see() {
print("Dog - see")
}
func run(){
print("Dog - run")
}
}
//定义一个变量
var animal: Animal
//创建Animal的对象,赋值给animal
animal = Animal()
//基类调用seapk,see,sleep函数
animal.speak()
animal.see()
animal.sleep()
//创建Dog的对象,也赋值给animal
animal = Dog()
//子类也调用seapk,see,sleep函数
animal.speak()
animal.see()
animal.sleep()
打印结果
Animal - Speak
Animal - see
Animal - sleep
Dog - Speak
Dog - see
Animal - sleep
根据对象不同,执行不同的函数。
问题3:swfit底层是怎么通过对象调用函数的?
使用xcode查看汇编代码,调用speak
函数主要汇编代码如下:
分析:
1.找到关键性汇编指令callq
调用函数。*0x50(%rcx)
,指将rcx
的值加上0x50
以后取出8个字节的内容。rcx
存储的是类型信息
,根据类型信息
偏移x50
找到函数speak
并调用。
2.取出寄存器%rax
里面存储8个字节赋值给寄存器%rcx
。获取寄存器rax
前八个字节的地址值并取出改地址值存储的内容,赋值给rcx
。这时的rcx
存储的是Animal
的类型信息
。
3.将0x23cc(%rip)
里面内存的8个字节给寄存器%rcx
,这里看注释,0x23cc(%rip)
就应该为变量animal
,找到animal
变量取出变量存储的堆空间
地址赋值给寄存器%rax
。
总结:
通过指针变量寻找对象的堆空间
,在根据堆空间
的前8个字节存储的指针
查找类型信息
的内存地址,从类型信息
偏移获取对象
的函数地址
值并进行调用。
多态的实现是根据对象的堆空间
查找前8个字节的类型信息
,不同类
的类型信息
是不相同的,每个函数都一个函数地址,这个函数地址在编译的时候就确认并存储到类型信息
里面。过程就是指针->堆空间->类型信息->地址偏移
。