2010-06-09 46 views
7

我最近接受了一個C/C++是主要語言的訪問,在一個問題中,我被告知可以使用vtable來確定層次結構中的哪個類一個基地指針實際存儲。如何使用vtable來確定班級類型

所以,如果,例如,你有

class A 
    { 
    public: 
    A() {} 
    virtual ~A() {} 
    virtual void method1() {} 
    }; 

    class B : public A 
    { 
    public: 
    B() {} 
    virtual ~B() {} 
    virtual void method1() {} 
    }; 

和你實例A * pFoo = new B(),是不是確實有可能使用虛函數表,以確定是否PFOO包含一個指向A或B的實例?

+0

感謝您的回覆。我忘記提及我詢問RTTI是否是他們正在尋找的東西,他們說,一般來說,他們禁用RTTI,所以不是這樣。他們正在尋找的解決方案完全有可能是Martin B所描述的 – 2010-06-11 18:36:38

回答

10

這顯然是依賴於實現的,但在大多數實現中,類AB的對象的內存中表示將以指向vtable的指針開始。你可以看看這個vtable指針,將它與你知道屬於類AB的對象的vtable指針進行比較,並以此方式確定對象的類。

爲了說明(當然這是什麼,但好作風):

A *pFoo=new B(); // pointer to object of unknown class (either A or B) 
A a; // Object known to be of class A 
B b; // Object known to be of class B 
void *vptrA=*((void **)&a); // Pointer to vtable of class A 
void *vptrB=*((void **)&b); // Pointer to vtable of class B 
void *vptrFoo=*((void **)pFoo); // Pointer to vtable of unknown object 
if(vptrFoo==vptrA) 
    printf("Class A\n"); 
else 
    printf("Class B\n"); 

重要:這是如何大多數實現工作的說明;除了依賴於實現之外,這種技術在存在多重繼承的情況下發生故障。你應該從來沒有在生產代碼中做這樣的事情;改爲使用RTTI。

+2

好的一個! :)。對於RTTI也是+1。 – Incognito 2010-06-09 14:46:28

1

您可以訪問vpointer,甚至可以通過vpointer調用任何虛擬方法。 但請記住這是EVIL。

實施例:

class A 
{ 
public: 
    void f1() 
    { 
     cout<<"bbb"<<endl;; 
    } 
    virtual void f2() 
    { 
     cout<<"ccc"<<endl;; 
    } 
    virtual void f3() 
    { 
     cout<<"ddd"<<endl;; 
    } 
}; 

,並調用在主

A a; 

typedef void (__thiscall* foo)(); 
(*(foo)((void**)(((void**)(&a))[0]))[1])(); 

它將訪問vpointer然後將由索引去並且將執行在V表的第二方法,該方法爲f3()。

另請注意按照已經建議的方法使用RTTI。

+0

哇!這是制動但很好!從來不想在面試中遇到這樣的問題。 – 2010-06-09 14:47:35

+0

這是如何回答具體問題的? – 2010-06-09 15:11:28

4

是的,這很有可能 - 使用dynamic_cast。這是一個非常糟糕的問題 - 稍微好一點的問題可能是「dynamic_cast如何實現?」但是如果在採訪中被問到,我不得不想知道面試官的好處。成爲一名優秀的或甚至是優秀的C++程序員並不需要依賴這樣的細緻的實現細節,但這些對於二次評估者來說當然是一個簡單的問題。