2011-01-22 42 views
6

這是一種作業問題。對於下面的代碼,如何用虛函數確定sizeof類?

#include <iostream> 
using namespace std; 

class A 
{ 
public: 
    virtual void f(){} 
}; 

class B 
{ 
public: 
    virtual void f2(){} 
}; 

class C: public A, public B 
{ 
public: 
    virtual void f3(){} 
}; 

class D: public C 
{ 
public: 
    virtual void f4(){} 
}; 

int main() 
{ 
    cout<<sizeof(D)<<endl; 
} 

輸出爲:8

任何人都可以請解釋它是如何爲8個字節?如果vtable的實現依賴於編譯器,那麼面試中這種問題應該怎麼回答?虛擬基類怎麼樣?

編輯:我正在一個32位平臺上工作。

+1

在大多數情況下,`sizeof`運算符對於類類型並不真正有意義。如果你依賴於某個類的大小,那麼你的設計在某處出錯的機率是很好的(但不是100%)。你能詳細說明你在作業中想要完成什麼,或者這是否是實際的作業問題? (如果是後者並且教師沒有指定特定的編譯器或平臺,那麼唯一正確的答案是「類的大小是實現細節」。) – 2011-01-22 05:46:36

+0

@Jonathan:我很久以前在筆試中遇到過這個問題,在多種選擇中沒有像「依賴實施」這樣的選擇。公司名稱是Phil ***。我想,我不能在這裏提到公司名稱:) – bjskishore123 2011-01-22 05:55:52

+0

那麼書面測試不允許正確的答案。這並不是不正確的。 「8字節」,「兩個指針」和「64位」都不是正確的答案,即使它在特定的系統/編譯器組合上是準確的。 – 2011-01-22 06:08:32

回答

13

這當然是依賴於實現的。這將是一個可怕的面試問題。一個好的C++程序員可以信任sizeof是正確的,讓編譯器擔心這些虛擬事物。

但是這裏發生的是一個典型的基於vtable的實現需要在類CD的對象中使用兩個vtable。每個基類都需要自己的vtable。 CD增加的新虛擬方法可以通過從一個基類擴展vtable格式來處理,但AB所使用的vtable不能組合使用。

在僞C代碼,這裏的類型d的最派生類對象的樣子對我實施(G ++ 4.4.5 Linux x86上):

void* D_vtable_part1[] = { (void*) 0, &D_typeinfo, &A::f1, &C::f3, &D::f4 }; 
void* D_vtable_part2[] = { (void*) -4, &D_typeinfo, &B::f2 }; 

struct D { 
    void** vtable_A; 
    void** vtable_B; 
}; 

D d = { D_vtable_part1 + 1, D_vtable_part2 + 1 }; 
0

原諒我含糊不清,但你提到它是本質上的功課。

查看sizeof()對其他類的返回值。你的答案將取決於你的編譯器以及你是否在32位或64位環境中。

快樂的偵探!

-2

對象的大小有與它有多少種方法無關,也不與這些方法是否爲虛擬。對象的大小由其成員變量確定爲,僅由確定。

我無法確切地告訴你爲什麼你會得到8字節的大小。由於在你的類中沒有數據成員,因此C++編譯器原則上可以生成一個根本不佔用空間的類[1]!我猜測這8個字節是提供一個指向vtbl的指針所需的最小值,以及可能的一些填充。

[1]我想。沒有時間檢查規範,目前找出sizeof是否可以返回0.

1

在這個問題上,如果你嘗試獲取的sizeof類A,它會給你答案'4',因爲A只有一個虛函數,所以它的__vptr將是'4'字節。同樣,如果你試圖獲得Sizeof B類,它會給你答案'4',因爲B也只有一個虛函數,所以它的__vptr將是'4'字節。

但是C類繼承了兩個類A & B和C本身有一個虛函數。所以C會收到2個__vptr指針,對於它自己的虛擬函數C將使用繼承的__vptr。 所以如果你試圖獲得Sizeof C類,它會給你答案'8',因爲C有兩個虛擬指針。

最後,D類繼承C類,因此D將爲其自己的虛函數使用繼承的__vptr,並且因爲C類的size爲'8'字節,所以sizeof D將給出答案'8'字節。

相關問題