掀起你的蓋頭來——談VC++物件模型

iDotNetSpace發表於2009-11-26
一個C++程式設計師,想要進一步提升技術水平的話,應該多瞭解一些語言的語意細節。對於使用VC++的程式設計師來說,還應該瞭解一些VC++對於C++的詮釋。Inside the C++ Object Model雖然是一本好書,然而,書的篇幅多一些,又和具體的VC++關係小一些。因此,從篇幅和內容來看,譯者認為本文是深入理解C++物件模型比較好的一個出發點。

這篇文章以前看到時就覺得很好,舊文重讀,感覺理解得更多一些了,於是產生了翻譯出來,與大家共享的想法。雖然文章不長,但時間有限,又若干次在翻譯時打盹睡著,拖拖拉拉用了小一個月。

一方面因本人水平所限,另一方面因翻譯時經常打盹,錯誤之處恐怕不少,歡迎大家批評指正。

1 前言

瞭解你所使用的程式語言究竟是如何實現的,對於C++程式設計師可能特別有意義。首先,它可以去除我們對於所使用語言的神祕感,使我們不至於對於編譯器乾的活感到完全不可思議;尤其重要的是,它使我們在Debug和使用語言高階特性的時候,有更多的把握。當需要提高程式碼效率的時候,這些知識也能夠很好地幫助我們。

本文著重回答這樣一些問題:
 * 類如何佈局?
 * 成員變數如何訪問?
 * 成員函式如何訪問?
 * 所謂的“調整塊”(adjuster thunk)是怎麼回事?
 * 使用如下機制時,開銷如何:
 * 單繼承、多重繼承、虛繼承
 * 虛擬函式呼叫
 * 強制轉換到基類,或者強制轉換到虛基類
 * 異常處理
首先,我們順次考察C相容的結構(struct)的佈局,單繼承,多重繼承,以及虛繼承;

接著,我們講成員變數和成員函式的訪問,當然,這裡麵包含虛擬函式的情況;
再接下來,我們考察建構函式,解構函式,以及特殊的賦值操作符成員函式是如何工作的,陣列是如何動態構造和銷燬的;
最後,簡單地介紹對異常處理的支援。

對每個語言特性,我們將簡要介紹該特性背後的動機,該特性自身的語意(當然,本文決不是“C++入門”,大家對此要有充分認識),以及該特性在微軟的VC++中是如何實現的。這裡要注意區分抽象的C++語言語意與其特定實現。微軟之外的其他C++廠商可能提供一個完全不同的實現,我們偶爾也會將VC++的實現與其他實現進行比較。

2 類佈局

本節討論不同的繼承方式造成的不同記憶體佈局。

2.1 C結構(struct)

由於C++基於C,所以C++也“基本上”相容C。特別地,C++規範在“結構”上使用了和C相同的,簡單的記憶體佈局原則:成員變數按其被宣告的順序排列,按具體實現所規定的對齊原則在記憶體地址上對齊。所有的C/C++廠商都保證他們的C/C++編譯器對於有效的C結構採用完全相同的佈局。這裡,A是一個簡單的C結構,其成員佈局和對齊方式都一目瞭然。


struct A {
char c;
int i;
};

譯者注:從上圖可見,A在記憶體中佔有8個位元組,按照宣告成員的順序,前4個位元組包含一個字元(實際佔用1個位元組,3個位元組空著,補對齊),後4個位元組包含一個整數。A的指標就指向字元開始位元組處。


2.2 有C++特徵的C結構


當然了,C++不是複雜的C,C++本質上是物件導向的語言:包含繼承、封裝,以及多型。原始的C結構經過改造,成了物件導向世界的基石——類。除了成員變數外,C++類還可以封裝成員函式和其他東西。然而,有趣的是,除非為了實現虛擬函式和虛繼承引入的隱藏成員變數外,C++類例項的大小完全取決於一個類及其基類的成員變數!成員函式基本上不影響類例項的大小。

這裡提供的B是一個C結構,然而,該結構有一些C++特徵:控制成員可見性的“public/protected/private”關鍵字、成員函式、靜態成員,以及巢狀的型別宣告。雖然看著琳琅滿目,實際上只有成員變數才佔用類例項的空間。要注意的是,C++標準委員會不限制由“public/protected/private”關鍵字分開的各段在實現時的先後順序,因此,不同的編譯器實現的記憶體佈局可能並不相同。(在VC++中,成員變數總是按照宣告時的順序排列)。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-620622/,如需轉載,請註明出處,否則將追究法律責任。

相關文章