2011-07-07 57 views
8

從我所瞭解的CPP中,每個類都有自己的vtable。虛擬表格/發送表

然而this維基百科的鏈接中提到:

一個對象的調度表將 包含的對象的 動態綁定方法的地址。方法 調用通過從對象的 調度表中取得 方法的地址來執行。調度表爲 ,對於屬於同一類的所有對象 相同,因此通常在它們之間共享 。

有人可以擺脫一些光。

謝謝!

+0

注 - 並非C++中的所有類都具有vtables。只有具有虛擬功能的人才有。如果沒有虛函數,則所有方法都可以靜態綁定(在編譯時),並且在運行時不需要調度機制。 – eran

回答

3

是的,編譯器和運行時對虛擬方法的處理方式不同。

Java: java中的所有方法默認都是虛擬的。這意味着任何方法在用於繼承時都可以被重寫,除非該方法被聲明爲final或static。

VM Specification

Java虛擬機不 任務的任何特定的內部 結構對象。該書標誌 有規定:在某些Sun的Java虛擬 機 實現的,一類 實例的引用是一個句柄的指針 本身就是一對指針:一個含有方法 表 對象和一個指向 對象的指針,該對象代表 對象的類型,另一個指向從堆中爲對象 數據分配的內存 。


C++:

每當一個類的成員函數被聲明爲虛擬的,編譯器,其中包含了聲明爲 在該類虛擬所有函數指針存儲器中創建一個 虛擬表。這使運行時多態性成爲可能(即在運行時找到所需的功能)。虛函數表還在 對象中有一個額外的指針指向vtable。由於這個額外的指針和vtable增加了對象的大小,所以類設計者需要明智地聲明函數是虛擬的。

事件在調用時在基部對象指針的方法,該序列爲:

  • 獲取虛表指針(這個虛表指針指向虛函數表的開頭)。
  • 使用偏移量獲取vtable中的函數指針。

通過vtable指針間接調用該函數。

0

該引用指出每個對象都有一個調度表,它可以在類中共享,因爲它們對於同一類的所有實例都是相同的。 I.E.每個班級都有自己的vtable。

+0

thnx ..你的意思是相反......每個類都有一個由其實例共享的調度表[objects] – codeObserver

1

每個具有虛擬功能的類(即在Java中它只是'每個類')都有它自己的vtable。每個對象都隱藏了對其類vtable的引用。因此,同一類的對象具有相同的引用。

當您虛擬方法的編譯器的調用通常使查找:

obj.method(args); 

被翻譯成什麼

obj.vtable[idx_method](obj, args); 

有時候,如果編譯器可以推斷出特定類型的對象,它可以發出靜態而不是虛擬。所以,代碼

MyObject obj(ctor_args); 
.... 
obj.method(args); 

可以翻譯成

MyObject_method(obj, args); 

通常將執行比虛擬呼叫更快。

9

它有時更容易用一個例子就明白了:

class PureVirtual { 
    public: 
     virtual void methodA() = 0; 
     virtual void methodB() = 0; 
}; 

class Base : public PureVirtual { 
    public: 
     virtual void methodA(); 
     void methodC(); 
    private: 
     int x; 
}; 

class Derived : public Base { 
    public: 
     virtual void methodB(); 
    private: 
     int y; 
}; 

因此,考慮到衍生它可能看起來像類型的對象:

      ------------ 
Known offset for vtable | 0xblah | -------> [Vtable for type "Derived"] 
         ------------ 
Known offset for x  | 3  | 
         ------------ 
Known offset for y  | 2  | 
         ------------ 

隨着V表類型「派生」找東西如:

      ------------ 
Known offset for "methodA" | 0xblah1 | ------> methodA from Base 
          ------------- 
Known offset for "methodB" | 0xblah2 | ------> methodB from Derived 
          ------------- 

請注意,由於「methodC」不是虛擬的,它不在vtable中在所有。還要注意Derived類的所有實例都有一個指向同一共享vtable對象的vtable指針(因爲它們具有相同的類型)。

雖然C++和Java的實現略有不同,但這些想法並不兼容。從概念的角度來看,關鍵的區別在於Java方法是「虛擬的」,除非聲明爲「最終」。在C++中,關鍵字「virtual」必須明確給出,以使函數在vtable中。任何不在vtable中的東西都將使用編譯時類型而不是對象的運行時類型來分派。