美文网首页
02汇编角度理解虚函数的实现

02汇编角度理解虚函数的实现

作者: bigCatloveFish | 来源:发表于2019-08-10 15:11 被阅读0次

    面向对象语言的三大特性 封装继承和多态。
    c++ 中的多态是通过虚函数实现的。
    我们声明一个Person类,然后 编写两个子类 一个为teacher 一个为progrommer

    class Person {
        int age;
    public:
        void  work(){
            cout <<"person work"<<endl;
        }
        void  speak() {
            cout << "person work" << endl;
        }
    };
    class Teacher :public Person{
        void work() {
            cout << "Teacher gogo" << endl;
        }
        void speak() {
            cout << "Teacher speak" << endl;
        }
    };
    class Programmer :public Person {
        void work() {
            cout << "code code" << endl;
        }
        void speak() {
            cout << "Programmer speak" << endl;
        }
    };
    

    然后 我们在代码中调用这两个类。

    #include <iostream>
    using namespace std;
    void doWork(Person *person) {
        person->work();
    } 
    // main() 是程序开始执行的地方 
    int main() {
        // 输出 Hello World
        Person *person1 = new Teacher();
        Person* person2 = new Programmer();
        doWork(person1);
        doWork(person2);
        delete person1;
        delete person2;
        return 0;
    }
    

    会发现打印结果如下


    1565415836(1).png

    并不会出现我们想要的结果。这个时候查看一下汇编会发现。这三个调用函数都指向了一个调用地址 03514B5h。显然这并不是我们想要的结果。如何才能得到我们想要的多态。
    这里就需要 使用到虚函数。虚函数的实现原理是虚函数表。虚表里面存放最终调用的函数地址。
    更该类的方法的声明方式如下

    class Person {
    public:
        int age;
        void virtual work(){
            cout <<"person work"<<endl;
        }
        void  virtual speak() {
            cout << "person work" << endl;
        }
    };
    

    然后调用

    int main() {
        Person* person11 = new Teacher();
        person11->age = 10;
        person11->speak();
        return 0;
    
    }
    

    会发现由原来的直接call 某个函数地址 变为

      mov         eax,dword ptr [person11]  //将person地址赋值给eax
      mov         edx,dword ptr [eax] //将exa 指向的内容也就是虚函数的地址赋值给edx  
      mov         esi,esp //未用到                 
      mov         ecx,dword ptr [person11]  
      mov         eax,dword ptr [edx+4] // 将edx 地址偏移4位地址的内容赋值给eax 这个地址 其实是 0x008f14e7 
      call        eax //调用 eax 其实是 call 0x008f14e7
    
    1565420671(1).png

    person地址中存放着虚函数表的地址

    1565420719(1).png

    虚函数表的地址中存放着虚函数的地址。

    相关文章

      网友评论

          本文标题:02汇编角度理解虚函数的实现

          本文链接:https://www.haomeiwen.com/subject/jqhrjctx.html