[轉(zhuǎn)]深度探索C++對(duì)象模型(3)

在學(xué)習(xí)完類對(duì)象的構(gòu)造后蟹肘,下面就需要學(xué)習(xí)類數(shù)據(jù)成員和函數(shù)成員的存取词疼。

編譯器對(duì)于類對(duì)象的處理方式:(1)對(duì)于空類,編譯器為該類添加一個(gè)char類型的成員帘腹,用來(lái)唯一標(biāo)識(shí)該類在內(nèi)存的位置(2)使用對(duì)齊機(jī)制贰盗,當(dāng)一個(gè)類的內(nèi)存字節(jié)數(shù)不足4的倍數(shù)將自動(dòng)補(bǔ)充,目的是為了尋址的方便

有些編譯器對(duì)于空類的處理進(jìn)行了優(yōu)化處理阳欲,僅當(dāng)該空類被繼承的時(shí)候舵盈,空類對(duì)象在子類對(duì)象中不占用任何內(nèi)存陋率,單獨(dú)空類的大小仍是1個(gè)字節(jié),這樣可能會(huì)避免對(duì)齊機(jī)制书释,優(yōu)化了C++對(duì)象模型的內(nèi)存空間翘贮。

但是對(duì)于非空類,不處理和優(yōu)化處理對(duì)于類對(duì)象的內(nèi)存空間沒(méi)有任何改變爆惧。

<pre>
class A{};
class X:public virtual A{};
class Y:public virtual B{};
Class Z:public X,public Y{}
</pre>

兩種處理機(jī)制得到的各個(gè)類的大欣暌场:

未優(yōu)化???????優(yōu)化后

??1 ????????????????1

??8 ????????????????4

??8 ????????????????4

??12????????????????8

一、數(shù)據(jù)成員深度探索

1扯再、數(shù)據(jù)成員在類中聲明的位置盡量靠前芍耘,雖然C++標(biāo)準(zhǔn)沒(méi)有規(guī)定聲明順序,但是為了防范全局變量和局部成員變量產(chǎn)生二義性熄阻,所以盡量在聲明函數(shù)前聲明全部變量斋竞。

inline函數(shù)在未定義之前不去去決斷其中使用的變量,但若聲明之后立即定義秃殉,則會(huì)判斷函數(shù)前聲明的變量坝初。

2、nostatic數(shù)據(jù)成員是在對(duì)象存儲(chǔ)空間中存放的钾军,static數(shù)據(jù)成員存在在靜態(tài)存儲(chǔ)區(qū)中鳄袍,每個(gè)類只用一份實(shí)例(除了模板類)。nostatic數(shù)據(jù)成員在內(nèi)存中的布局要求是:在同一訪問(wèn)權(quán)限段(public private protected)中吏恭,晚聲明的成員的地址比早聲明的成員的地址高即可拗小,不要求相鄰。

3樱哼、編譯器為了實(shí)現(xiàn)某種機(jī)制為類對(duì)象添加的成員哀九,如vptr指針,它的存放位置C++標(biāo)準(zhǔn)并沒(méi)有限制搅幅,可以放在對(duì)象首部阅束,也可以放在尾部。放在首部方便了對(duì)虛函數(shù)調(diào)用盏筐,放在尾部可以與C語(yǔ)言中的結(jié)構(gòu)體相兼容围俘,各有好處,視編譯器而定琢融。

4、數(shù)據(jù)成員的存取

考慮通過(guò)對(duì)象存取成員和通過(guò)對(duì)象指針存取成員有什么區(qū)別簿寂?

(1)static數(shù)據(jù)成員的存取

由于static數(shù)據(jù)成員存儲(chǔ)在程序的靜態(tài)存儲(chǔ)區(qū)中漾抬,當(dāng)通過(guò)類對(duì)象、對(duì)象指針或者類::方式存取該成員是常遂,編譯器將內(nèi)部轉(zhuǎn)化為對(duì)靜態(tài)變量的存取纳令。因?yàn)閟tatic數(shù)據(jù)成員并不存儲(chǔ)在類對(duì)象空間中,所以對(duì)靜態(tài)成員的存取不需要經(jīng)過(guò)對(duì)象,因此通過(guò)對(duì)象和指針存取static變量沒(méi)有任何差異平绩。

<strong>若取static數(shù)據(jù)成員的地址圈匆,將會(huì)得到該成員在內(nèi)存中的實(shí)際地址,而且其指針類型和普通指針類型是相同的捏雌,而nostatic數(shù)據(jù)成員則有所區(qū)別跃赚。</strong>

static int a;為一個(gè)A類中的一個(gè)static成員性湿,聲明一個(gè)指向它的指針應(yīng)該這樣聲明:int *p=&A::a;指針的使用也和普通指針相同纬傲。

(2)nostatic數(shù)據(jù)成員的存取

nostatic數(shù)據(jù)成員的存取必須通過(guò)對(duì)象或指向?qū)ο蟮闹羔槪驗(yàn)閚ostatic數(shù)據(jù)成員的地址依賴于對(duì)象的存儲(chǔ)地址肤频,編譯器會(huì)在存取nostatic成員時(shí)加上this指針(指向?qū)ο蟮钠鹗嫉刂罚┨纠ǎㄟ^(guò)this指針和nostatic成員在對(duì)象中的offset值存取該成員。

換句話說(shuō)宵荒,nostatic數(shù)據(jù)成員的物理地址可表示為this+offset汁雷。

所以,取某個(gè)類中的nostatic數(shù)據(jù)成員地址得到的是該成員在對(duì)象中存儲(chǔ)offset报咳,即&A::b轉(zhuǎn)化成指針類型就是int A::p=&A::b;想要使用p還需要通過(guò)對(duì)象才能完成如a.p==a.b;

<strong>注意:&A::b的到的值在編譯器端將會(huì)自動(dòng)加1侠讯,也就是說(shuō)真實(shí)的offset=&A::b-1,這樣做的目的是為了區(qū)別空的指向數(shù)據(jù)成員指針(0)和非空指向數(shù)據(jù)成員指針。當(dāng)調(diào)用指針的時(shí)候首先將指針值減1少孝,如果是空的成員指針的話將不能調(diào)用继低。這樣就可以把空指針(0)和指向首部成員的指針(0)分開(kāi)。</strong>

例如int A::P1=0;int A::p2=&A::b;則p2的值是1(假設(shè)b放在對(duì)象首部稍走,vptr在尾部)袁翁,當(dāng)調(diào)用時(shí)想將p2-1+this獲取成員地址,空指針則是-1婿脸。

1)單一繼承(非虛擬繼承):子類總是把基類對(duì)象放在子類對(duì)象的首部粱胜,然后才放子類自己的成員。因此狐树,子類通過(guò)對(duì)象或者通過(guò)對(duì)象指針訪問(wèn)基類成員不會(huì)存在間接性焙压,基類成員在編譯期就可以確定其offset值(基類成員在基類中的offset值和在子類中的offset值是一樣的)。因?yàn)榛悓?duì)象在子類對(duì)象的首部抑钟,這樣當(dāng)基類指針被子類賦值時(shí)涯曲,基類指針仍然指向基類對(duì)象起始地址。

<strong>當(dāng)存在多態(tài)時(shí)在塔,編譯器會(huì)自動(dòng)根據(jù)vptr的位置修改數(shù)據(jù)成員的offset值幻件。</strong>

2)多重繼承(非虛擬繼承):此種情況較上述情況麻煩,需要編譯器進(jìn)行地址轉(zhuǎn)換蛔溃〈铝ぃ基類按照繼承生命的順序在繼承類中排列篱蝇,因此第一個(gè)基類的地址不需要轉(zhuǎn)化,直接復(fù)制即可徽曲。而處于中間的基類的地址就需要通過(guò)this+中間類的大小才能夠確定零截,這個(gè)工作由編譯器完成。地址轉(zhuǎn)化的時(shí)候首先判斷子類地址是否為零秃臣。

<strong>這種情況下涧衙,存取基類對(duì)象中的成員在編譯器是就確定了offset值,因此通過(guò)對(duì)象和指針訪問(wèn)基類對(duì)象不會(huì)存在差異甜刻。</strong>

3)虛擬繼承:虛擬繼承使得繼承類無(wú)論繼承多少個(gè)虛擬基類绍撞,都會(huì)只包含一個(gè)虛擬基類對(duì)象。那么得院,虛擬基類對(duì)象在繼承類對(duì)象內(nèi)存分布中就只存在一個(gè)基類對(duì)象實(shí)例∩迪常現(xiàn)在通用的是將虛擬基類對(duì)象放在繼承類對(duì)象的尾部,繼承類其他成員在虛擬基類對(duì)象上面祥绞。

Paste_Image.png

那么非洲,<strong>虛擬基類對(duì)象在每個(gè)繼承類中的offset值是不同的,因此如果通過(guò)對(duì)象指針存取基類對(duì)象成員蜕径,不能在編譯期確定基類成員的offset值两踏。</strong>但是,通過(guò)對(duì)象存取基類成員時(shí)是在編譯期確定offset值兜喻。

比如:

Vertex3D v3d梦染;
Point3D *p=&v3d;

那么p->_x的步驟是:v3d的this指針指向Point3D子對(duì)象的地址傳遞給p,然后通過(guò)p查詢虛表找到虛擬基類對(duì)象的地址朴皆,再根據(jù)offset進(jìn)行相應(yīng)的修改即可存取_x帕识。

如果還按照之前的offset值,_X在Point3D中的offset是13遂铡,但是_x在Vertex3D中offset不是13肮疗,這樣就可能提取錯(cuò)誤的值,因此扒接,對(duì)虛擬基類對(duì)象成員的提取將通過(guò)虛表間接獲得基類對(duì)象的地址進(jìn)行轉(zhuǎn)換伪货。

<strong>在虛擬繼承時(shí),使用對(duì)象和對(duì)象指針存取基類對(duì)象成員會(huì)產(chǎn)生差異钾怔,使用對(duì)象指針存取基類對(duì)象成員時(shí)碱呼,必須等到運(yùn)行期進(jìn)行判斷指針指向的真正類型才能確定offset值。</strong>

原文地址:http://www.cnblogs.com/tracylee/archive/2012/12/19/2825397.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宗侦,一起剝皮案震驚了整個(gè)濱河市巍举,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凝垛,老刑警劉巖懊悯,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異梦皮,居然都是意外死亡炭分,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門剑肯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)捧毛,“玉大人,你說(shuō)我怎么就攤上這事让网⊙接牵” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵溃睹,是天一觀的道長(zhǎng)而账。 經(jīng)常有香客問(wèn)我,道長(zhǎng)因篇,這世上最難降的妖魔是什么泞辐? 我笑而不...
    開(kāi)封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮竞滓,結(jié)果婚禮上咐吼,老公的妹妹穿的比我還像新娘。我一直安慰自己商佑,他們只是感情好锯茄,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著茶没,像睡著了一般肌幽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上礁叔,一...
    開(kāi)封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天牍颈,我揣著相機(jī)與錄音,去河邊找鬼琅关。 笑死煮岁,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的涣易。 我是一名探鬼主播画机,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼新症!你這毒婦竟也來(lái)了步氏?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤徒爹,失蹤者是張志新(化名)和其女友劉穎荚醒,沒(méi)想到半個(gè)月后芋类,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡界阁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年侯繁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泡躯。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贮竟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出较剃,到底是詐尸還是另有隱情咕别,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布写穴,位于F島的核電站惰拱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏确垫。R本人自食惡果不足惜弓颈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望删掀。 院中可真熱鬧翔冀,春花似錦、人聲如沸披泪。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)款票。三九已至控硼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間艾少,已是汗流浹背卡乾。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缚够,地道東北人幔妨。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像谍椅,于是被迫代替她去往敵國(guó)和親误堡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容