2017-06-19 78 views
3

我知道的是,空類的大小是1,只是爲了符合不允許大小的對象(及其類)爲0的標準。在這裏,我得到了派生類D的大小爲2.爲什麼行爲在這種情況下是不同的 假設沒有數據成員或虛擬指針從類B和C繼承到D?爲什麼從兩個空類派生的空類的大小是2?

#include<iostream> 
using namespace std; 

class A {}; 
class B : public A {}; 
class C : public A {}; 
class D : public B, public C {}; 

int main() { 
    cout<<"Size of D is: "<<sizeof(D)<<endl; 
    return 0; 
} 
+0

也許是因爲它由兩個大小爲1的基類組成? –

+0

@o_weisman但實際上,這些基類的大小爲0,只是爲了每個對象被分配不同的內存,大小設置爲1,與D類的情況相同,這應該是什麼行爲。 – cbinder

+1

@DrorMeirovich您提到的問題的參考資料是關於虛擬指針的,但在這種情況下,類是空白的,並且沒有涉及數據成員(包括虛擬指針)的繼承。 – cbinder

回答

3

對我來說,似乎無論是否空基地優化可以應用在這裏,取決於如何解釋[intro.object/8]

除非對象是一個位域或基類的子對象大小爲零,那個對象的地址就是它所佔用的第一個字節的地址。 兩個對象一個,並用重疊的不 位字段壽命b 可以具有相同的地址,如果一個被嵌套在所述 其他,或者如果至少一個是零大小和 的基類子對象它們的不同類型;否則,他們有不同的地址。

BC不同類型?他們都是A。實際上有兩個不同的A對象。允許編譯器編寫器分別在BC處單獨停止分配存儲,而不檢查A是否爲空。

值得一提的是,與G ++大小回到1,如果你有B獨立基地C繼承:

Live Example

#include<iostream> 

class A {}; 
class A1 {}; 
class B : public A {}; 
class C : public A1 {}; 
class D : public B, public C {}; 

int main() { 
    std::cout << "Size of D is: " << sizeof(D) << std::endl; 
    return 0; 
} 
2

這是因爲你繼承兩個基類自己派生自相同的基類A,查看當您將程序更改爲此時輸出如何變化

#include<iostream> 
using namespace std; 

class A {}; 
class Z {}; 
class B : public A {}; 
class C : public Z {}; 
class D : public B, public C {}; 

int main() { 
    cout<<"Size of D is: "<<sizeof(D)<<endl; 
    return 0; 
} 

正如你現在看到的D大小1

的問題是類似於可怕的鑽石,你可能知道的。編譯器試圖在您的示例中消除D中存在的A這兩個實例。而空基地優化這裏不適用,該標準不要求它和編譯器不執行(見下文)


該標準明確允許編譯器不應用空基地優化多重繼承的情況下。從標準here

相關報價允許標準佈局類有基類強制編譯器實現了標準佈局類空基地優化,這可能會破壞編譯器的應用程序二進制接口(ABI)。見上面9.2/18。這被認爲不是現代編譯器關心的問題,除了可能在多重繼承的情況下。由於多重繼承不是本建議的核心,因此如果證明存在爭議,允許標準佈局類或其基礎使用多重繼承將從提議中消除。

+0

我不認爲有鑽石相關的歧義,因爲沒有符號可以解決。 – cbinder

+0

@cbinder但它們都從相同的基類繼承,當發生這種情況時,編譯器不需要將基類視爲空基,因爲它需要消除這兩個基的歧義。 – Curious

+0

@cbinder從標準中添加了一個引用 – Curious