• 虚函数初探


    今天读了coolshell博主几年前的旧文,C++虚函数表解析,代码如下:

    #pragma once
    
    #include <iostream>
    
    using namespace std;
    
    class Base
    {
    public:
        virtual void f(){ cout<<"Base::f()"<<endl;}
        virtual void g(){ cout<<"Base::g()"<<endl;}
        virtual void h(){ cout<<"Base::h()"<<endl;}
    private: 
        virtual void p(){cout<<"Base::p(private)"<<endl;}
    };
    
    class Base1
    {
    public:
        virtual void f(){ cout<<"Base1::f()"<<endl;}
        virtual void g(){ cout<<"Base1::g()"<<endl;}
        virtual void h(){ cout<<"Base1::h()"<<endl;}
    };
    
    class Base2
    {
    public:
        virtual void f(){ cout<<"Base2::f()"<<endl;}
        virtual void g(){ cout<<"Base2::g()"<<endl;}
        virtual void h(){ cout<<"Base2::h()"<<endl;}
    };
    
    class Base3
    {
    public:
        virtual void f(){ cout<<"Base3::f()"<<endl;}
        virtual void g(){ cout<<"Base3::g()"<<endl;}
        virtual void h(){ cout<<"Base3::h()"<<endl;}
    };
    
    class Derive:public Base1,public Base2,public Base3
    {
    public:
        virtual void f(){ cout<<"Derive::f()"<<endl;}
        virtual void g1(){cout<<"Derive::g1()"<<endl;}
    };
    
    typedef void (*Func)(void);
    
    int main()
    {
        Base b;
        Func pFun = NULL;
        cout<<"虚函数表的地址:"<<(int*)(&b)<<" "<<(void*)(&b)<<endl;
        cout<<"虚函数表中第一个函数的位置:"<<(int*)*reinterpret_cast<int*>(&b)<<
            " "<<(int*)*(int*)(&b)<<endl;
        pFun = (Func)*((int*)*(int*)(&b)); //Base::f()
        pFun();
        pFun = (Func)*((int*)*(int*)(&b) + 1);
        pFun();
        pFun = (Func)*((int*)*(int*)(&b) + 2);
        pFun();
        pFun = (Func)*((int*)*(int*)(&b) + 3); //通过虚函数表调用父类private虚函数
        pFun();
    
        Derive d;
        int** pVtab = (int**)&d;
        //Base1's vtable
        //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+0);
        pFun = (Func)pVtab[0][0];
        pFun();
    
        //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+1);
        pFun = (Func)pVtab[0][1];
        pFun();
    
        //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+2);
        pFun = (Func)pVtab[0][2];
        pFun();
    
        //Derive's vtable
        //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+3);
        pFun = (Func)pVtab[0][3];
        pFun();
    
        //The tail of the vtable
        pFun = (Func)pVtab[0][4];
        cout<<pFun<<endl;
    
    
        //Base2's vtable
        //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+0);
        pFun = (Func)pVtab[1][0];
        pFun();
    
        //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+1);
        pFun = (Func)pVtab[1][1];
        pFun();
    
        pFun = (Func)pVtab[1][2];
        pFun();
    
        //The tail of the vtable
        pFun = (Func)pVtab[1][3];
        cout<<pFun<<endl;
    
    
    
        //Base3's vtable
        //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+0);
        pFun = (Func)pVtab[2][0];
        pFun();
    
        //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+1);
        pFun = (Func)pVtab[2][1];
        pFun();
    
        pFun = (Func)pVtab[2][2];
        pFun();
    
        //The tail of the vtable
        pFun = (Func)pVtab[2][3];
        cout<<pFun<<endl;
        system("pause");
        return 0;
    }

    下面是一点感悟:

    1.为什么只能通过强行把&b转成int *,取得虚函数表的地址。转换成(char*)或者(void*)就没法正确获取地址?

    比如这样:(int*)*(char*)(&b) 或者(char*)*(char*)(&b)。(void*)*(int*)(&b),(char*)*(int*)(&b)可获得正确的结果。

    突然意识到这也算问题?在32位的编译器设置下指针占用的地址为4byte和int类型一样,*(T*)(&b)只要获取一个产度为4byte的值作为函数指针的地址即可,也就是说T的长度需要和指针产度一致才能获取正确的地址,例如:(long*)*(long*)(&b),也可获取虚函数表的地址。

    2.虚函数表的结构:

    i.一般继承(无虚函数覆盖):虚函数表类似一个一维数组的链式结构

    表中存的是虚函数的地址:

    获取虚函数表的地址:(int*)(&b)

    获取虚函数表中第一个函数的地址:(int*)*(虚函数表的地址 + 0)

    第二个函数的地址:(int*)*(虚函数表的地址 + 1)

    ii.多重继承的时候虚函数表的结构类似如一个二维数组,每一行对应一个基类的虚函数序列:

    int** pVtab = (int**)(&derive);

  • 相关阅读:
    Mysql源码学习——Connection Manager
    MySQL源码学习——MDL字典锁
    Mysql源码学习——用户认证原理与实现
    Mysql源码学习——Thread Manager
    你真的了解如何登录MySQL么?
    CSDN密码库窥视各大数据库性能
    Mysql源码学习——没那么简单的Hash
    How to use NoSQL in MySQL
    Oracle的聚簇也Hold不住了
    Python 错误解决方法
  • 原文地址:https://www.cnblogs.com/fripside/p/2952707.html
Copyright © 2020-2023  润新知