2011-12-30 58 views
2

假設有一個名爲Person的類,它包含一個名爲age()的虛函數。根據語言語義,vtable是每個類而不是每個對象。它是每個對象的VPTR,並指向vtable。vtable中虛函數的地址

問題:

如果我建立這個程序(可以說main()的存在):

  1. 將虛函數表中創建即可以VTABLE自帶存在W/O甚至創建一個對象?

  2. 編譯器放入vtable for age()的地址是一種內存中的某種靜態地址嗎?

  3. 或者它是編譯器內部創建一些對象來獲取age()的地址(因爲age()將在一些數據成員上工作,這些數據成員只有在構造對象時纔會存在)或者有一些這背後的其他魔法?

按我的理解,答覆如下:

  1. 不知道

我試圖在上面運行的程序 「納米」 剛看看我能不能找出虛擬表,但沒有運氣。有沒有辦法做到這一點?

請建議。

+4

這一切都取決於實現,所以你必須指定你使用哪個編譯器,如果你想要一個實際的答案。 – 2011-12-30 19:06:33

+0

*根據語言語義* ...語言甚至沒有提及*虛擬表*或*虛擬表指針*,而是可以用虛擬表實現的操作的語義(如在所有當前編譯器中)或與任何其他方法 – 2011-12-30 19:12:12

+0

謝謝@EtiennedeMartel – 2011-12-30 21:17:55

回答

0

「根據語言語義,」沒有vtable這樣的東西。 C++規範沒有詳細說明如何實現虛擬調度。編譯器可以使用vtables。或者可以使用別的東西;這取決於編譯器。

當然,一個特定的編譯器可以使用vtables。但它可以隨心所欲地做任何事情;這是一個實現細節。總之,沒有調查你正在使用的特定編譯器,你就無法知道。

真的,這有什麼關係嗎?

+0

從Bruce Eckel,我瞭解實現,因此認爲這是C++如何定義它的。但是,你是對的。這應該是編譯器依賴的。感謝您糾正我的理解。 – 2011-12-30 21:13:57

1

所有這些答案都完全依賴於編譯器。沒有要求物理vtbl甚至存在;這只是執行該語言的一種非常常見的方式。但是對於這些,並沒有普遍的ABI,並且這不像開發人員應該擔心的那樣。

+0

明白了,謝謝。 – 2011-12-30 21:16:16

3

因爲它是定義所有的實現,我的回答描述了一些「共同實施」

  1. 的v表由操作系統存儲在可執行文件就像機器代碼本身,並加載到內存裝載機。操作系統無需關心要加載的數據:字符串文字,機器代碼,vtable,常量數據等等......

  2. 假設您有:

    struct A { 
        int x; 
        virtual void f() { cout << x; } 
    }; 
    
    void g(A* a) { a->f(); } 
    

    生成的代碼看起來(語義)類似:

    // pseudocode, not C++ 
    struct A { 
        void *vtable; 
        int x; 
    }; 
    
    void A_f(A* this) { cout << this->x; } 
    
    void* A_vtable[] = { &A_f }; 
    
    void g(A* a) { ((void(*)(A*))(((void**)a->vtable)[0]))(a); } 
    

    所以,是的,它是靜態數據。

    當然,上面的代碼是非常簡單的。要支持RTTI和虛擬繼承,你必須做更復雜的事情。

  3. 我不明白你的意思,但號

+0

你有一個很好的解釋。這也說明了我Q3以及:) – 2011-12-30 21:26:48

1

這是所有編譯器相關的,你應該採取的全部答案,就像一種方式,它可以做到:

這個vtable是否會被創建,也就是說vtable是否可以創建,即使創建一個單獨的對象?

取決於編譯器和程序。例如,GCC將在翻譯單元中創建vtable,其中定義了類定義中未定義的第一個虛擬函數(是否創建了任何對象),但在某些情況下可能根本不會生成vtable或者即使沒有創建對象,它也可能會生成一個。

編譯器放入vtable for age()的地址是一種內存中的一些靜態地址嗎?

這通常由鏈接器/加載程序解決。當程序被鏈接時,鏈接器通常會解析函數的(相對)地址,並將這些地址注入到vtable中作爲第一步。當程序被加載到內存中時,這些地址被固定到函數所在的內存地址(這取決於加載程序會因執行而異)。

或者它是編譯器在內部用於獲得地址年齡()(因爲年齡()將被工作的一些數據成員可進來存在一個對象被構造僅當)產生了一些對象或有這背後還有其他魔法?

我不太關注整個問題。編譯器不會創建具有成員age類型的任何對象,只有在您的程序請求它時纔會這樣做。成員函數可能訪問/修改給定類型的對象的數據成員,但是通過傳遞給所有非靜態成員的隱式指針來處理對這些成員的訪問。

+0

謝謝@David .. – 2011-12-30 21:28:32