對象模型(Object Model):甚麼是對像模型?對象模型就是把原本都是代碼的程序,將其圖形化,把它們各自的關係都表現出來,讓人更好理解,每個對象或是類的關聯性
vptr:英文就是virtual pointer,就是虛擬指針的意思,跟指針有相似的特徵,比如說:他的內存占用也是4byte,而它的功用是把每個類的對象所擁有的虛函數,用一個指針指出,而且不管多少的虛函數,都只有一個虛擬指針,這樣好處,我們會再下面再討論
vtbl:英文就是virtual table,就是虛擬表格的意思,這個其實就是存放虛函數的地方,而他也是與virtual pointer共同存在的,因為virtual pointer就是將指針指向他
先給出一個例子,這個例子出自於老師的課件:
創造出三個類,分別是A,B,C,這三個類,這三者的關係是繼承,B繼承A,C繼承B,代碼如下:
<span style="font-size:18px;"><span style="font-size:18px;">class A
{
public:
virtual void vfuncl();
virtual void vfunc2();
void func1();
void func2();
private:
int m_data1,m_data2;
};
class B:public A
{
public:
virtual void vfunc1();
void func3();
private:
int m_data3;
};
class C: public B
{
public:
virtual void vfunc1();
void func4();
private:
int m_data1;
int m_data2;
}
</span>
關係圖示:
我們現在就可以知道這三個類之間的關係,然後我們再把他的內存情況畫出
我們可以看出整個內存與虛函數的情況在繼承關係下是怎麼樣的!而了解了對象模型,vptr和vtbl之後,我們就可以開始學習動態綁定,同時比較靜態綁定,同時我們必須先知道,繼承數據是內存的繼承,而繼承內存是調用權的繼承,跟內存無關,只是權力的繼承
我們先假設
<span style="font-size:18px;">C* p=&c;</span>
設p是指向C的指針,我們通過p調用c::vunc1()
靜態綁定:
這是在C語言所用的方法,他會再編譯器中利用call,找到地址,調用函數,由於本篇的重點在動態綁定,所以此方法著墨較少
動態綁定:
這是在C++中所用的方法,我們先看他的代碼表達式:
<span style="font-size:18px;">(*p->vptr[n])(p)</span>
我們就來走一遍思路,首先通過p要調用c::vunc1(),因為p是指向c的,而func1()是虛函數,所以我們可以想出
<span style="font-size:18px;">p->vptr
</span>
因為要調用c::vunc1(),就先把p指向vptr,再讓vptr指向vtbl,就可以想到
<span style="font-size:18px;">p->vptr[n]</span>
這裡的n就是在vtbl這個表格中,想像他是數組,而n就是他所存放的位置
<span style="font-size:18px;">(*p->vptr[n])(p)</span>
就是編譯器在動態綁定時,所做的反應,同時動態綁定是由編譯器所決定的
最後我們在總結一下,動態綁定的優缺點以及他的條件:
優點:
1.其是通過虛函數實現的,而虛函數是通過一張表格(virtual table)實現的。這個表中記錄了虛函數的位址,解決繼承、覆蓋的問題,保證使用時能夠根據物件的實際類型調用正確的函數
2.因為期的所有傳遞都是以指針的方式解決,效率高
缺點:
1.動態繫結在函式呼叫時需要在虛函數表中查找,所以性能比靜態函式呼叫稍低
2.通过父类类型的指针访问子类自己的虚函数将发生错误
條件:
1.必須通過指針調用,如:C* p=&c;
2.這個指針必須向上轉型(up-cast),也就是要子類的指針訪問父類的虛函數
3.調用的必須是虛函數