2016-08-26 44 views
-5

在閱讀了關於名稱修改的更多信息後,我對vtable感到困惑。 爲前:從C++中的vtable函數解析

class Base 
{ 
public: 
    virtual void print() 
    { 
    } 
}; 

class A : public Base 
{ 
public: 
    void hello() 
    { 
     .... 
    } 

    void print() 
    { 
    } 
}; 

A obj; 
obj.hello(); 

Base* test = new A(); 
test->print(); 

按名稱manging obj.hello()電話後我的理解將被轉換爲類似_ZASDhellov(&obj)現在

  1. 如何虛函數將虛函數表被調用?
  2. 我狂猜test->__vtable[_ZASDprintv](&test(dynamic cast to derived???))是正確的?
  3. 如何從vtable中解析函數名稱?
+4

'A :: hello()'不是一個虛函數。 – tkausl

+0

沒有虛函數,因此在你顯示的代碼中沒有vtable。 –

+0

我知道。如果它是一個虛擬函數將如何評估? –

回答

3

首先,vtables不是C++語言的一部分,而是特定編譯器使用的實現細節。下面我描述一種常用的方式。

二,您的功能hello不是虛擬的。爲了使其虛擬化,您只需將virtual預先聲明爲聲明。

假設它現在是虛擬的:你的猜測非常接近。實際上,vtable(其中一個指針與虛擬類的每個實例一起存儲)是一個函數指針數組。一個特定功能在其中被查找的方式是它的順序。 A中的第一個聲明的虛擬函數是其第一個條目vtable,第二個是第二個條目等等。如果A有基類,表中第一個(非覆蓋)虛擬函數索引A將爲n+1,其中n是其基類的最後一個虛函數的索引。如果A具有多個基類,則它們的條目按其基本類A的聲明順序位於A的條目前面。

如果A使用虛擬繼承,則圖片比這更復雜一些,除非特別感興趣,否則我不會詳細說明。

更新:我會根據請求添加一個非常簡短的虛擬繼承案例說明。如果A具有Base作爲虛擬基類,則Avtable將在開始處(在函數地址之前)存儲Base的數據在A對象內開始的字節偏移量。這是必要的,因爲與普通繼承不同,基類沒有將其數據放在派生類的數據之前 - 而是遵循它。所以實際上,對Base中定義的虛擬函數的任何函數調用都必須使其指針偏移該數量的this。此外,Base必須擁有自己的vtable指針,就在它希望找到它的數據的開頭。因此完整的A對象將包含兩個vtable指針而不是一個。第二個指針指向的實際vtable將與第一個指針vtable相同,除了高級跳過上面描述的偏移量條目(因此任何使用vtableBase代碼都會在它開頭的地方找到第一個虛擬函數預期)。除了這些差異之外,vtable本身與以前相同。

+0

我會這樣說:「如果'A'有一個基類,'A'的索引是第一個......」 - 我花了幾秒鐘才意識到「it」的前奏是'A',而不是「基礎班」。 +1提到虛擬繼承(它接近我說「因爲魔法」的地步)。 –

+0

我收錄了你的建議,謝謝 – Smeeheey

+0

謝謝@Smeeheey現在圖片很清楚。如果您可以解釋A是否使用虛擬繼承,將會很有幫助。 –