2010-07-04 14 views
2

我在Wikipedia的虛擬表上閱讀過一篇文章。C++中成員函數的內存實現

class B1 
{ 
public: 
    void f0() {} 
    virtual void f1() {} 
    int int_in_b1; 
}; 

class B2 
{ 
public: 
    virtual void f2() {} 
    int int_in_b2; 
}; 

used to derive the following class: 

class D : public B1, public B2 
{ 
public: 
    void d() {} 
    void f2() {} // override B2::f2() 
    int int_in_d; 
}; 

看完之後我不禁納悶虛成員函數是如何非用C++實現。是否有像所有功能地址存儲在其中的v-表一樣的單獨表格?如果是,那麼調用這張表是什麼,在繼承過程中會發生什麼?

如果沒有,那麼編譯器如何理解這些語句?

D * d1 = new D; 
d1->f0(); // statement 1 

如何編譯解釋說F0()是B1功能和自d曾公開繼承d它可以訪問F0()。根據這篇文章的編譯器變動幅度爲1〜

(*B1::f0)(d) 

回答

7

非虛擬成員函數的實現類似於接受隱藏的this參數的全局函數。編譯器知道基於繼承樹調用哪個方法,所以不需要運行時表。

1

除了​​,我只能說是一個正常的成員函數是一個類中只是一個內存地址(我甚至認爲,該類的每個對象使用相同的在內存中的「函數指針」,但有自己的變量)。 v表是運行時重定向的一種形式,因爲編譯器無法知道它正在處理什麼對象(顯然是由於多態性)。

+0

有沒有像虛函數表爲所有非虛函數一個單獨的表,所述指針被存儲在所有的類對象,並且得到由遺傳派生類? – Bruce 2010-07-04 13:51:48

+0

@Bruce:請參閱Amnon的答案以獲得更清晰的信息,以及adf88的技術性答案。 – rubenvb 2010-07-05 14:40:33

1

是否有一個單獨的表,如所有的函數地址存儲在v表中?

它們存儲在被調用的地方。

舉個例子:只要f0方法是非虛擬的,編譯器知道它是什麼地址,因爲只有一種可能性。讓地址爲0xABCD。然後代碼

d1->f0(); // statement 1 

被編譯的指令:

// push onto the stack 'this' pointer, as you pointed out the address must 
// be earlier translated from D class to B1 which is not presented here 
push d1 

call 0xABCD // call method at known address (jump to this address)