2014-10-20 65 views
0
class C 
{ 
public: 
    C() : m_x(0) { } 
    virtual ~C() { } 

public: 
    static ptrdiff_t member_offset(const C &c) 
    { 
     const char *p = reinterpret_cast<const char*>(&c); 
     const char *q = reinterpret_cast<const char*>(&c.m_x); 

     return q - p; 
    } 

private: 
    int m_x; 
}; 

int main(void) 
{ 
    C c; 
    std::cout << ((C::member_offset(c) == 0) ? 0 : 1); 
    std::cout << std::endl; 

    std::system("pause"); 
    return 0; 
} 

以上程序輸出1。它所做的只是檢查c對象的地址和c的字段m_x。它打印出1這意味着地址不相等。我的猜測是,這是因爲編譯器是虛擬的,所以編譯器必須爲該類創建一個vtable並將vpointer放入該類的對象中。如果我已經錯了,請糾正我。vpointer在對象中的位置

顯然,它將vpointer放在對象的開頭,將m_x字段推得更遠,從而給它一個不同的地址。是這樣嗎?如果標準指定了vpointer在對象中的位置?根據wiki它是實現相關的。它的位置可能會改變程序的輸出。

那麼你能否總是預測這個程序的輸出而不指定目標平臺?

回答

1

在C++中沒有「vpointers」。多態性和動態分派的實現留給編譯器,並且不會以任何方式指定生成的類佈局。當然,只給予基礎子對象的視圖時,多態類型的對象將不得不攜帶額外的狀態以標識具體類型。

vtables和vptrs的實現很常見並且很流行,並且將vptr放在類的開頭意味着您不需要對單個繼承向上和向下轉換進行任何指針調整。

很多C++編譯器都遵循(部分)Itanium ABI for C++,它指定類似這樣的類佈局決定。這popular article也可能提供一些見解。

1

是的,它依賴於實現,不,不知道目標平臺/編譯器,無法預測程序的輸出。

2

實際上,它幾乎總是以這種方式佈置的。但是,C++標準允許使用任何作品。我可以想象幾種解決方案不需要滿足上述要求 - 儘管它們可能不能很好地解決問題。

但是請注意,如果您有多個繼承,則可以擁有一個以上的vptr/vtable。