C 物件模型筆記 物件的三種記憶體布局

2021-04-24 09:28:41 字數 2839 閱讀 7328

下面的c++

**定義了乙個類

point:

現在定義

point

的乙個物件pt:

point pt;

這個筆記討論的問題就是:如果讓你設計這個物件的記憶體布局,你會怎麼設計它?(記憶體布局在這裡指的是物件各個成員在記憶體的排放)

下面給出

lippman

在《深度探索

c++物件模型》中提出的三種可能的記憶體布局。 一、

簡單的方式(原文是:

****** object model)

point pt

;如下圖所示:

下面我們來看看這樣的布局怎麼實現多型?

以上面的虛函式

print

為例子,如以上的**。我的辦法就是:呼叫虛函式的時候,先查詢派生類的部分,有沒有指向

print

的指標(在本例中,有);如果有,就呼叫派生類的,如果沒有,再到基類那邊去找。

是不是感到有些眼熟啊?比如在

mfc訊息對映的實現**中

…可以參考在下寫的「

mfc訊息對映原理」

2、對於派生類的第二種布局就是把基類的成員直接嵌入派生類裡面去。

關於多型的實現也是通過類似於上面的第一種派生布局的方法來實現的,即先找派生類的,再找基類的。

其實,這種布局還有第三個優點,那就是減少了編譯依賴,比如突然有一天,你要在類裡面改乙個成員的名字,或者改乙個成員函式的實現,這種布局,只需要重新編譯類的實際定義的地方就可以了,關於類的物件及其使用的地方,都可以不用編譯(不過對於增加或者減少成員的時候就不行)

優點說完了,好像也挺好的;不過根據中國的偉大的陰陽學說,下面該說缺點了:

不知看到了上面的三個優點,你發現了什麼?不知道有沒有看見,漏了乙個重要的東西,那就是

---效率;效率是

c++的最重要的指標之一(

c++的兩條最重要的指標:與

c相容,追上

c的效率);所以,缺點就是沒有效率。

具體分析一下,每個物件都放著指向本類的成員函式的指標,這樣會造成大量的重複。多型的時候,還得先找派生類,再找基類,會浪費了大量的時間;又浪費時間又浪費空間的做法,

c++怎麼可以接受呢?所以這種記憶體布局不出現在實際的

c++編譯當中。但是,這種做法啟發了

lippman

他們,發明了:指向物件成員的指標

二、**驅動(

table-driven

)的記憶體布局

還是上面的

point

類的物件

pt,看一下這種模型是什麼東東?

**驅動的記憶體模型,比起上面的第一種布局,還多了乙個間接層,那樣做的好處就是:在擴充套件成員的時候,

pt本身的布局沒有變,還是兩個**,變的只是定義的東西,編譯器就可能會根據這些情況來優化布局,使得減少編譯依賴。

缺點嘛,不用說,上面的那個簡單的記憶體布局都已經是低效而不為

c++所接收的了,更何況這個,馬上就淘汰出局了。不過這個模型也給

lippman

一些啟發:發明了虛函式表。

關於這個模型在繼承的情況下究竟是如何的?下面畫個圖看看:

關於**驅動的簡介:

以上的布局,由於物件的記憶體裡面只是兩個指標指向兩個相應的**,所以叫做**驅動;**驅動在很多地方都用的到,比如:有限狀態機(編譯原理和

ip順便說一句,其實

mfc裡面的訊息對映的做法,與其說是參考第一種布局,還不如說參考第二種布局,用的就是**驅動(類似的還有

qt的訊號與槽,

vcl的事件機制等等)

三、c++

中真實的物件的記憶體布局

千呼萬喚始出來,終於到正題了。說道這裡,想起一句經典:「美女這東西,就像鮮花一樣,需要綠葉的陪襯才顯示出她的嬌美」~

綠葉已經介紹完畢,下面看鮮花,呵呵。

下面的重點在於解釋一下這個記憶體布局的特點:

1、非靜態(

nonstatic

)資料成員,每個物件的記憶體空間裡面有乙份。

2、靜態資料成員,靜態與非靜態的成員函式,在整個記憶體裡面只有乙份實體。

3、定義了虛函式的每乙個類,都有乙份虛函式表;表項裡面放的是這個類的相關的函式呼叫(等一下畫個關於繼承的看看就知道了)

4、每個定義了虛函式的類的物件裡面都有乙個指標(像上面的

_vptr_point),

指向本類的虛函式表。

注意:1

)、如果有定義了兩個物件

point pt1; point pt2;

那麼pt1

,和pt2

的_vptr_point

指向的都是同乙個**。

*(pt1._vptr_point) == *(pt2._vptr_point)

,因為每個類的虛函式表只有乙份!2)、

_vptr_point

只是為了說明問題而模擬出來的,也就是說

c++程式是不能訪問這個東西的。(為了顯示我的博學,寫個詩句在這裡做驗證:不識廬山真面目,只緣身在此山中),所以你不能通過

c++本身來理解

c++底層的機制,只能通過更為底層的語言(彙編,或者機器碼,甚至可以用

0-1電流來理解都是可以滴)

缺點就是上面二種型別的優點,這個優點就是上面兩種模型的缺點,就這麼簡單。

下面以point2d

的記憶體布局圖結束這篇筆記吧。(

_vptr_point2d

所指向的這個**就是

point2d

的虛函式表,留意一下和上面的

point pt

的布局有什麼不同)

關於這個模型對

c++的影響到底有多大,請看下文

~ps.

c++物件模型》的第一章第一節。

C 物件模型筆記 物件的三種記憶體布局

下面的c 定義了乙個類point view plaincopy to clipboardprint?class point class point 現在定義point的乙個物件pt point pt 這個筆記討論的問題就是 如果讓你設計這個物件的記憶體布局,你會怎麼設計它?記憶體布局在這裡指的是物件...

C 三種記憶體物件比較

摘自 c 將記憶體劃分為三個邏輯區域 堆 棧和靜態儲存區。既然如此,我稱位於它們之中的物件分別為堆物件,棧物件以及靜態物件。三種記憶體物件的比較 棧物件的優勢是在適當的時候自動生成,又在適當的時候自動銷毀,不需要程式設計師操心 而且棧物件的建立速度一般較堆物件快,因為分配堆物件時,會呼叫operat...

C 物件模型和布局(三種經典類物件記憶體布局)

侯捷翻譯的 深度探索c 物件模型 一書中,對c 物件模型進行了三種典型模型劃分,分別為簡單物件模型 a object model 驅動物件模型 a table drive object model c 物件模型 the c object model 本文以及之後的部落格主要總結的都是最後乙個c 物件...