標籤:Object Storage Service 程式 ace 一個 view 運行 類對象 通過 而在
參考:http://www.weixueyuan.net/view/6372.html
總結:
在C++中通過虛成員函數表vtable實現多態,虛函數表中儲存的是類中虛函數的入口地址。
使用多態會降低程式運行效率,使用多態的程式會使用更多的儲存空間,儲存虛函數表等內容,而且在調用函數時需要去虛函數表中查詢函數入口地址,這會增加程式已耗用時間。
在設計程式時,程式設計人員可以選擇性的使用多態,對於有需要的函數使用多態,對於其它的函數則不要採用多態。
通常情況下,如果一個類需要作為基類,並且期望在衍生類別中修改某成員函數的功能,並且在使用類對象的時候會採用指標或引用的形式訪問該函數,則將該函式宣告為虛函數。
通過前兩節的介紹,想必對多態有一定的瞭解了。這一節將介紹多態是如何?的,關於如何?多態,對於程式設計人員來說即使不知道也是完全沒有關係的,但是對於加深對多態的理解具有重要意義,故而在此節中稍微闡述一下多態的實現機制。
在C++中通過虛成員函數表vtable實現多態,虛函數表中儲存的是類中虛函數的入口地址。在普通的類中是沒有虛函數表的,只有在具有虛函數的類中(無論是自身添加的虛函數還是繼承過來的虛函數)才會具有虛函數表,通常虛成員函數表的首地址將會被存入對象的最前面(在32位的作業系統中,儲存地址是用4個位元組,因此這個首地址就會佔用對象的前四個位元組的空間)。
例1:#include<iostream>using namespace std;class base{public: virtual void v1(){ } virtual void v2(){ }};class derived: public base{public: virtual void v1(){ } virtual void v2(){ }};int main(){ base b; derived d; base *p; p = &b; p->v1(); p->v2(); p = &d; p->v1(); p->v2(); return 0;}
我們將兩個類定義成例1所示形式,兩個類中各有兩個虛函數v1和v2,我們將其函數入口地址找到列於下表中:
| 虛成員函數 |
函數入口地址 |
虛成員函數 |
函數入口地址 |
| base::v1 |
00D15834 |
derived::v1 |
00D15844 |
| base::v2 |
00D15838 |
derived::v2 |
00D15848 |
虛函數表裡面儲存的就是虛函數的入口地址。我們再來看主函數,在主函數中先定義了base類對象b,因為b類中有虛函數,因此存在虛函數表,而虛函數表的首地址就儲存在對象所在儲存空間的最前,具體情況可以見。當然聲明derived對象d之後,情況也跟中一樣,同樣在Object Storage Service空間中包含虛成員函數表地址。
之後定義了一個基類類型的指標p,當我們通過基類指標p調用虛函數v1或v2時,系統會先去p所指向的對象的前四個位元組中尋找到虛函數表地址,之後在記憶體中找到該虛函數表,然後在表中找到對應函數的入口地址,之後直接存取這個函數了。當p指標指向的是基類對象時,基類的虛函數表將會被訪問,基類中虛函數將會被調用。當p指標指向的是衍生類別對象,則訪問的是衍生類別的虛函數表,衍生類別的虛函數表中存的是衍生類別中的虛函數入口地址,因此調用的是衍生類別中的虛函數。
使用多態會降低程式運行效率,使用多態的程式會使用更多的儲存空間,儲存虛函數表等內容,而且在調用函數時需要去虛函數表中查詢函數入口地址,這會增加程式已耗用時間。在設計程式時,程式設計人員可以選擇性的使用多態,對於有需要的函數使用多態,對於其它的函數則不要採用多態。通常情況下,如果一個類需要作為基類,並且期望在衍生類別中修改某成員函數的功能,並且在使用類對象的時候會採用指標或引用的形式訪問該函數,則將該函式宣告為虛函數。
4.3 C++虛成員函數表vtable