虛擬函式的實現原理

weixin_33935777發表於2018-12-05

首先虛擬函式是通過一張虛擬函式表來實現的,在加上虛擬函式關鍵字的時候 物件例項會增加虛擬函式表的指標!
注意是表的指標 如果存表 那麼所有類都要加 會變得非常的大

2954412-6cd684f8173e045d.png
image.png

這裡我們建了一個空類 可以發現這個空類大小是1
(空類 編譯器會插入一個char 為了保證這個類的例項在記憶體中有唯一地址)
2954412-7dc2b2bca493101e.png
image.png

  • 這裡大小變成了4個位元組 這4個位元組就是虛擬函式表的地址
  • 這也說名物件存的是虛擬函式表的指標 不是表


    2954412-5a0a6e408e404506.png
    image.png

虛擬函式表 這裡有三個虛擬函式


2954412-a07785378f33c0f4.png
image.png

2954412-a5f4a573bf95103f.png
image.png

2954412-0f7ae3e840e0a78b.png
image.png

2954412-8f07fc4a3831d790.png
image.png

直接通過虛擬函式表找到虛擬函式

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; }

};

class derive : public Base {

public:

    virtual void f() { cout << "derive Base::f" << endl; }

    virtual void g() { cout << "derive Base::g" << endl; }

    virtual void h() { cout << "derive Base::h" << endl; }

};



typedef void(*Fun)(void);

int main()
{
    Base b;
    derive der;

    Fun pFun = NULL;
    cout << "Virtual Address:" << (int*)(&b) << endl;
    cout << "Virtual Table - First Funcation Address:" << (int*)*(int*)(&b) << endl;

    int *pV_Address = (int*)(&b);           //虛擬函式表的地址
    int *pV_Table = (int *)*pV_Address;     //虛擬函式的地址
    pFun = (Fun)*pV_Table;                  //取虛擬函式
    //pFun = (Fun)*((int*)*(int*)(&b));
    pFun();

    cout << "Virtual Address:" << (int*)(&der) << endl;
    cout << "Virtual Table - First Funcation Address:" << (int*)*(int*)(&der) << endl;

    pV_Address = (int*)(&der);           //虛擬函式表的地址
    pV_Table = (int *)*pV_Address;     //虛擬函式的地址
    pFun = (Fun)*pV_Table;                  //取虛擬函式
    pFun();

    system("pause");
    return 0;
}
2954412-5a92736496c030c3.png
image.png
  • 可以看到基類和派生類各自都有一張虛擬函式表
  • 這樣就能保證虛擬函式在不同的類中能執行不同的函式

相關文章