美文网首页
多态--虚函数

多态--虚函数

作者: const_qiu | 来源:发表于2020-08-25 21:31 被阅读0次

    1.通过对象调用成员函数(无虚函数)

    • 源代码
    
    class Base {
    public:
        void Function_1() {
            printf("func1...\n");
        }
        void Function_2() {
            printf("func2...\n");
        }
    
    };
    
    
    int main()
    {
        Base  base;
        base.Function_1();
        base.Function_2();
    
    }
    
    
    • 反汇编代码
        Base  base;
        base.Function_1();
    00D419E2 8D 4D F7             lea         ecx,[base]  
    00D419E5 E8 45 F9 FF FF       call        Base::Function_1 (0D4132Fh)  
        base.Function_2();
    00D419EA 8D 4D F7             lea         ecx,[base]  ;ecx = this指针,对象首地址
    00D419ED E8 5C F8 FF FF       call        Base::Function_2 (0D4124Eh) ; E8 call 直接调用
    

    2. 通过对象调用成员函数(有虚函数)

    class Base {
    public:
        void Function_1() {
            printf("func1...\n");
        }
        virtual void Function_2() {
            printf("func2...\n");
        }
    
    };
    
    
    int main()
    {
        Base  base;
        base.Function_1();
        base.Function_2();
    
    }
    
    
        Base  base;
    009C1A82 8D 4D F4             lea         ecx,[base]  
    009C1A85 E8 C4 F7 FF FF       call        Base::Base (09C124Eh)  
        base.Function_1();
    009C1A8A 8D 4D F4             lea         ecx,[base]  ;
    009C1A8D E8 C0 F8 FF FF       call        Base::Function_1 (09C1352h)  
        base.Function_2();
    009C1A92 8D 4D F4             lea         ecx,[base]  ;;
    009C1A95 E8 3D F6 FF FF       call        Base::Function_2 (09C10D7h)  ;
    
    • 对比发现通过对象调用普通函数与虚函数的汇编代码没有区别,都是E8 call(直接调用)

    3. 通过对象指针调用成员函数(有虚函数)

    类中有虚函数时(无继承),类的大小会增加4字节,存放的是一个指向虚表的指针,虚表指针存放在对象首地址

    class Base {
    public:
        void Function_1() {
            printf("func1...\n");
        }
        virtual void Function_2() {
            printf("func2...\n");
        }
    
    };
    
    
    int main()
    {
        Base  base;
        Base* pb = &base;
        pb->Function_1(); 
        pb->Function_2(); 
    
    }
    
    
      Base  base;
    00BF1A82 8D 4D F4             lea         ecx,[base]  
    00BF1A85 E8 C4 F7 FF FF       call        Base::Base (0BF124Eh)  
        Base* pb = &base;
    00BF1A8A 8D 45 F4             lea         eax,[base]  
        Base* pb = &base;
    00BF1A8D 89 45 E8             mov         dword ptr [pb],eax  
        pb->Function_1(); 
    00BF1A90 8B 4D E8             mov         ecx,dword ptr [pb]  
    00BF1A93 E8 BA F8 FF FF       call        Base::Function_1 (0BF1352h)  ;普通函数还是直接调用
        pb->Function_2(); 
    00BF1A98 8B 45 E8             mov         eax,dword ptr [pb]  
    00BF1A9B 8B 10                mov         edx,dword ptr [eax]  
    00BF1A9D 8B F4                mov         esi,esp  
    00BF1A9F 8B 4D E8             mov         ecx,dword ptr [pb]  
    00BF1AA2 8B 02                mov         eax,dword ptr [edx]  ;
    00BF1AA4 FF D0                call        eax  ; FF call 是间接调用,eax存的是某个虚函数地址
    

    4. 通过虚表指针调用虚函数

    class Base {
    public:
        Base() {
            int  x = 1;
            int  y = 1;
    
        }
        int x;
        int  y;
        void Function_1() {
            printf("func1...\n");
        }
        virtual void Function_2() {
            printf("func2...\n");
        }
        virtual void Function_3() {
            printf("func3...\n");
        }
        virtual void Function_4() {
            printf("func4...\n");
        }
        virtual void Function_5() {
            printf("func5...\n");
        }
    };
    
    //定义一个函数指针类型
    
    typedef void(*pFunction)(void);
    int main()
    {   
        pFunction pFn;
    
        Base  base;
        Base* pb = &base;
        //对象的前四个字节为虚表指针
        //printf("base的虚表地址为:%d\n",*(int*)&base);
        //通过虚表指针调用虚函数
        
        for (int i = 0; i < 4; i++) {
            int tmp = *((int*)(*(int*)&base) + i);
            pFn = (pFunction)tmp;
            pFn();
    
        }
        /*pb->Function_1(); 
        pb->Function_2(); */
    
    }
    

    5 有继承关系打印虚表

    5.1 单继承无函数重写

    struct Base {
    public:
        Base() {
            int  x = 1;
            int  y = 1;
    
        }
        int x;
        int  y;
        virtual void Function_1() {
            printf("base:func1...\n");
        }
        virtual void Function_2() {
            printf("base:func2...\n");
        }
        virtual void Function_3() {
            printf("base:func3...\n");
        }
        
    };
    
    struct Sub :Base {
    
    
        virtual void Function_4() {
            printf("Sub:func4...\n");
        }
        virtual void Function_5() {
            printf("Sub:func5...\n");
        }
        virtual void Function_6() {
            printf("Sub:func6...\n");
        }
    
    
    };
    
    //定义一个函数指针
    
    typedef void(*pFunction)(void);
    int main()
    {   
        pFunction pFn;
    
        Sub  sub;
        Base* pb = &sub;//父类指针指向子类对象
        //对象的前四个字节为虚表指针
        //printf("base的虚表地址为:%d\n",*(int*)&base);
        //通过虚表指针调用虚函数
        
        for (int i = 0; i < 6; i++) {
            int tmp = *((int*)(*(int*)&sub) + i);
            pFn = (pFunction)tmp;
            pFn();
    
        }
        /*pb->Function_1(); 
        pb->Function_2(); */
    
    }
    
    • 运行结果:
    base:func1...
    base:func2...
    base:func3...
    Sub:func4...
    Sub:func5...
    Sub:func6...
    

    5.2 单继承有函数重写

    struct Base {
    public:
        Base() {
            int  x = 1;
            int  y = 1;
    
        }
        int x;
        int  y;
        virtual void Function_1() {
            printf("base:func1...\n");
        }
        virtual void Function_2() {
            printf("base:func2...\n");
        }
        virtual void Function_3() {
            printf("base:func3...\n");
        }
        
    };
    
    struct Sub :Base {
    
    
        virtual void Function_1() {
            printf("Sub:func1...\n");
        }
        virtual void Function_2() {
            printf("Sub:func2...\n");
        }
        virtual void Function_6() {
            printf("Sub:func6...\n");
        }
    
    };
    
    //定义一个函数指针
    
    typedef void(*pFunction)(void);
    int main()
    {   
        pFunction pFn;
        Sub  sub;
        Base* pb = &sub;//父类指针指向子类对象
        //对象的前四个字节为虚表指针
        //printf("base的虚表地址为:%d\n",*(int*)&base);
        //通过虚表指针调用虚函数
        
        for (int i = 0; i < 4; i++) {
            int tmp = *((int*)(*(int*)&sub) + i);
            pFn = (pFunction)tmp;
            pFn();
    
        }
        /*pb->Function_1(); 
        pb->Function_2(); */
    
    }
    
    • 运行结果: 子类覆盖父类中同名的
    Sub:func1...
    Sub:func2...
    base:func3...
    Sub:func6...
    

    5.3 多继承无函数重写

    多继承,假如有两个直接父类,会有两张虚表,对象的前八个字节为两个虚表指针

    #include <iostream>
    #include <stdio.h>
    using namespace std;
    struct Base1 {
    
        virtual void Function_1() {
            printf("base1:func1...\n");
        }
        virtual void Function_2() {
            printf("base1:func2...\n");
        }
        virtual void Function_3() {
            printf("base1:func3...\n");
        }
        
    };
    struct Base2 {
    
        virtual void Function_4() {
            printf("base2:func4...\n");
        }
        virtual void Function_5() {
            printf("base2:func5...\n");
        }
        virtual void Function_6() {
            printf("base2:func6...\n");
        }
    
    };
    
    struct Sub :Base1,Base2 {
        int x = 5;
        int y = 6;
    
        virtual void Function_7() {
            printf("Sub:func7...\n");
        }
        virtual void Function_8() {
            printf("Sub:func8...\n");
        }
        virtual void Function_9() {
            printf("Sub:func9...\n");
        }
    
    };
    
    //定义一个函数指针
    
    typedef void(*pFunction)(void);
    int main()
    {   
        pFunction pFn;
        Sub  sub;
    
        //Base* pb = &sub;//父类指针指向子类对象
        //对象的前四个字节为虚表指针
        
        //通过虚表指针调用虚函数
        //打印第一张虚表
        printf("打印第一张虚表\n");
        printf("第一张虚表地址为:%ld\n", *(int*)&sub);
        for (int i = 0; i < 6; i++) {
            int tmp = *((int*)(*(int*)&sub) + i);
            pFn = (pFunction)tmp;
            pFn();
    
        }
        printf("打印第二张虚表\n");
        printf("第二张虚表地址为:%ld\n", *(int*)((int)&sub+4));
        //打印第二张虚表
        pFunction pFn2;
        for (int i = 0; i < 3; i++) {
            int tmp = *((int*)(*(int*)((int)&sub + 4)) + i);
            pFn2 = (pFunction)tmp;
            pFn2();
    
        }
    
    }
    
    • 运行结果
    打印第一张虚表
    第一张虚表地址为:1690464
    base1:func1...
    base1:func2...
    base1:func3...
    Sub:func7...
    Sub:func8...
    Sub:func9...
    打印第二张虚表
    第二张虚表地址为:1691084
    base2:func4...
    base2:func5...
    base2:func6...
    

    5.4 多继承有函数重写

    #include <iostream>
    #include <stdio.h>
    using namespace std;
    struct Base1 {
    
        virtual void Function_1() {
            printf("base1:func1...\n");
        }
        virtual void Function_2() {
            printf("base1:func2...\n");
        }
        virtual void Function_3() {
            printf("base1:func3...\n");
        }
        
    };
    struct Base2 {
    
        virtual void Function_4() {
            printf("base2:func4...\n");
        }
        virtual void Function_5() {
            printf("base2:func5...\n");
        }
        virtual void Function_6() {
            printf("base2:func6...\n");
        }
    
    };
    
    struct Sub :Base1,Base2 {
        int x = 5;
        int y = 6;
    
        virtual void Function_1() {
            printf("Sub:func1...\n");
        }
        virtual void Function_4() {
            printf("Sub:func4...\n");
        }
        virtual void Function_7() {
            printf("Sub:func7...\n");
        }
    
    };
    
    //定义一个函数指针
    
    typedef void(*pFunction)(void);
    int main()
    {   
        pFunction pFn;
        Sub  sub;
    
        //Base* pb = &sub;//父类指针指向子类对象
        //对象的前四个字节为虚表指针
        
        //通过虚表指针调用虚函数
        //打印第一张虚表
        printf("打印第一张虚表\n");
        printf("第一张虚表地址为:%ld\n", *(int*)&sub);
        for (int i = 0; i < 4; i++) {
            int tmp = *((int*)(*(int*)&sub) + i);
            pFn = (pFunction)tmp;
            pFn();
    
        }
        printf("打印第二张虚表\n");
        printf("第二张虚表地址为:%ld\n", *(int*)((int)&sub+4));
        //打印第二张虚表
        pFunction pFn2;
        for (int i = 0; i < 3; i++) {
            int tmp = *((int*)(*(int*)((int)&sub + 4)) + i);
            pFn2 = (pFunction)tmp;
            pFn2();
    
        }
    
    }
    
    • 运行结果

    重写的是哪个就在哪个表里

    打印第一张虚表
    第一张虚表地址为:13028192
    Sub:func1...
    base1:func2...
    base1:func3...
    Sub:func7...
    打印第二张虚表
    第二张虚表地址为:13028812
    Sub:func4...
    base2:func5...
    base2:func6...
    

    5.5 多层继承无函数重写

    多层继承只有一个虚表

    #include <iostream>
    #include <stdio.h>
    using namespace std;
    struct Base1 {
    
        virtual void Function_1() {
            printf("base1:func1...\n");
        }
        virtual void Function_2() {
            printf("base1:func2...\n");
        }
        
        
    };
    struct Base2:Base1 {
    
        virtual void Function_3() {
            printf("base2:func4...\n");
        }
        virtual void Function_4() {
            printf("base2:func5...\n");
        }
        
    };
    
    struct Sub :Base2 {
        
        virtual void Function_5() {
            printf("Sub:func5...\n");
        }
        virtual void Function_6() {
            printf("Sub:func6...\n");
        }
    
    
    };
    
    //定义一个函数指针
    
    typedef void(*pFunction)(void);
    int main()
    {   
        pFunction pFn;
        Sub  sub;
    
        //Base* pb = &sub;//父类指针指向子类对象
        //对象的前四个字节为虚表指针
        
        //通过虚表指针调用虚函数
        //打印第一张虚表
        printf("打印第一张虚表\n");
        printf("第一张虚表地址为:%ld\n", *(int*)&sub);
        for (int i = 0; i < 6; i++) {
            int tmp = *((int*)(*(int*)&sub) + i);
            pFn = (pFunction)tmp;
            pFn();
    
        }
        //printf("打印第二张虚表\n");
        //printf("第二张虚表地址为:%ld\n", *(int*)((int)&sub+4));
        ////打印第二张虚表
        //pFunction pFn2;
        //for (int i = 0; i < 3; i++) {
        //  int tmp = *((int*)(*(int*)((int)&sub + 4)) + i);
        //  pFn2 = (pFunction)tmp;
        //  pFn2();
    
        //}
    
    }
    
    • 运行结果:
    打印第一张虚表
    第一张虚表地址为:4967372
    base1:func1...
    base1:func2...
    base2:func4...
    base2:func5...
    Sub:func5...
    Sub:func6...
    

    5.5 多层继承有函数重写

    #include <iostream>
    #include <stdio.h>
    using namespace std;
    struct Base1 {
    
        virtual void Function_1() {
            printf("base1:func1...\n");
        }
        virtual void Function_2() {
            printf("base1:func2...\n");
        }
        
        
    };
    struct Base2:Base1 {
    
        virtual void Function_3() {
            printf("base2:func3...\n");
        }
        virtual void Function_4() {
            printf("base2:func4...\n");
        }
        
    };
    
    struct Sub :Base2 {
        
        virtual void Function_1() {
            printf("Sub:func1...\n");
        }
        virtual void Function_3() {
            printf("Sub:func3...\n");
        }
    
    
    };
    
    //定义一个函数指针
    
    typedef void(*pFunction)(void);
    int main()
    {   
        pFunction pFn;
        Sub  sub;
    
        //Base* pb = &sub;//父类指针指向子类对象
        //对象的前四个字节为虚表指针
        
        //通过虚表指针调用虚函数
        //打印第一张虚表
        printf("打印第一张虚表\n");
        printf("第一张虚表地址为:%ld\n", *(int*)&sub);
        for (int i = 0; i < 4; i++) {
            int tmp = *((int*)(*(int*)&sub) + i);
            pFn = (pFunction)tmp;
            pFn();
    
        }
        //printf("打印第二张虚表\n");
        //printf("第二张虚表地址为:%ld\n", *(int*)((int)&sub+4));
        ////打印第二张虚表
        //pFunction pFn2;
        //for (int i = 0; i < 3; i++) {
        //  int tmp = *((int*)(*(int*)((int)&sub + 4)) + i);
        //  pFn2 = (pFunction)tmp;
        //  pFn2();
    
        //}
    
    }
    
    • 运行结果:
    打印第一张虚表
    第一张虚表地址为:6015948
    Sub:func1...
    base1:func2...
    Sub:func3...
    base2:func4...
    

    相关文章

      网友评论

          本文标题:多态--虚函数

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