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函数主要汇编代码如下:

![tmp2e8ebba3.png](https://img.haomeiwen.com/i1605700/36e81a7bbd668102.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

分析:
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

tmp4772c205.png tmp2018b686.png tmp2e8ebba3.png

总结:

通过指针变量寻找对象的堆空间,在根据堆空间的前8个字节存储的指针查找类型信息的内存地址,从类型信息偏移获取对象函数地址值并进行调用。
多态的实现是根据对象的堆空间查找前8个字节的类型信息,不同类型信息是不相同的,每个函数都一个函数地址,这个函数地址在编译的时候就确认并存储到类型信息里面。过程就是指针->堆空间->类型信息->地址偏移

上一篇下一篇

猜你喜欢

热点阅读