




下載本文檔
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、C/C+ 關于C+的類對象,內存分布問題-答王富濤同學原文出處C+對象內存布局C+虛函數表解釋C+內存布局(上)C+內存布局(下)深度探索 C+對象模型原問題如下:#include <iostream>using namespace std;class basepublic:virtual void fun1();void fun2();int main()base s;cout<<sizeof(s)<<endl;return 0;代碼的結果為4。這個我覺得是因為那個虛函數表里的一個指針占了4個字節但是如果我去掉virtual 代碼的結果為1類中的普通成員函
2、數占對象的空間嗎?數據成員所占空間的計算是否也是和結構體類似呢?這個就不明白了,請各位指點。我的回答如下:這個涉及到類和結構體,在C+內部的排列方式。我也不是很了解,只能就自己了解的一點知識做點回答,歡迎大家指正。編譯器在編譯每個類時,不管這個類以后會實例化幾個對象,首先,它會提取這些類的共性,放到一起,做成一個表。比如類里面的非虛函數,這類函數,所有的對象共享一段函數代碼,自然沒有必要每個對象內部都設置一個函數指針,這太浪費內存了。因此,一個類,所有的非虛函數,會被編譯器排成一個符號表,放置在特定的編譯期基礎變量區。這實際表現看,是放在exe文件里面的,在調用一個程序時,是直接從文件中讀出,
3、并經過地址修訂,準備使用,這部分連基棧都算不上,算是常量區了,所有的常量也是放在這個區。嗯,函數內部的靜態變量,類中的靜態變量,靜態函數,都是這個區。那,除掉這些,類里面還有什么呢?還有虛函數,我們知道,虛函數表示可能繼承,事實上,多次(不是多重)繼承后,一個類的虛函數內部會有一個棧,每個虛函數都有一個棧,每次調用該函數,會從棧頂開始call,當然,如果程序員愿意,也可以在繼承的虛函數內部,通過調用父類的同名虛函數,逐級向上call,直至call完所有的虛函數為止。這就說明,虛函數和普通成員函數不同,每個對象都有可能變化,因此,編譯器就不敢把這個函數的指針,放在常量區,必須跟著對象走,注意,不
4、是類,類是沒有實體的,因此,不存在sizeof,只有對象存在大小。(sizeof只能計算棧內存(局部變量)的大小,不能計算全局變量和動態申請(malloc)的內存大小,參考程序員面試寶典二P57和P252的筆記)還有就是普通成員變量,這些內容,每個對象也是不一樣的,因此,每個對象必須自己建立一個表來管理,否則大家就混了。因此,我們知道了,每個類,實例化對象之后,其實對象的實體在內存中的存儲,就只包含虛函數和普通成員變量,這是C+編譯器為了節約內存做得優化。我們回到你的代碼看,你的代碼中,fun2是普通函數,被編譯器放到常量區去了,因此,不占用對象空間,虛函數fun1,則需要占用,我們知道,32
5、位操作系統,一個指針是4Bytes,函數指針也是指針,因此,你的結果是4Bytes。取消了virtual 之后,fun1也變成了普通函數,因此和fun2等同處理,就不再占用對象空間,因此,對象空間為0了。類的虛函數,表現為一個函數指針棧,棧底,是基類這個函數的指針,往上,實際上是繼承類,該虛函數的繼承函數的指針,一個類,被繼承幾次,比如3次,最后一次繼承,這個棧就有3層。有點繞。舉個例子吧class Avirtual void Func(void);class B : public Avirtual void Func(void);class C : public Bvirtual void
6、Func(void);這個A類,里面的Func指針就是它自己B就是一個棧,棧底是A:Func,棧頂是B:Func而C就是三層的棧了,在B的基礎上,棧頂有壓入了C:Func基本上就是這個管理關系。我的話的意思是,在任何一層繼承函數,都可以去手動去call父類的對應函數,完成對整個棧鏈上所有函數的調用。因為我們知道,一個類的虛函數,一旦被繼承,原來的父類函數指針就被壓倒棧下面去了,從棧頂看,只有最后一層的函數指針。比如C這個類看,我們看它的Func,只要它繼承并實現了,那么,調用Func一定只能調用C:Func,B和A的由于看不到,因此是不會被調用的。當然,如果C沒有實現這個虛函數,則Func的棧
7、上,沒有C:Func,因此,直接Call會Call到B:Func,以此類推,如果B沒有實現這個虛函數,表示未繼承,則Call會Call到A:Func,這就是虛函數繼承中,后實現的覆蓋前實現的原理。當然,如果A內沒有實現Func的實體,做了一個純虛函數,而B和C這些繼承類也不實現,那么,編譯器在構造符號表的時候,就會找不到任何一個Func的實體,該虛函數棧為空,無法連接,因此會報連接失敗的錯誤,編譯不能通過。這種棧式管理,有好有壞,好處是后面的繼承類,可以選擇實現虛函數,也可以選擇不實現,偷個懶。程序不會出錯,下次調用該函數,會自動沿著它的繼承關系,尋找父類以及更往前的爺爺類的函數實體,至少能找
8、到一個執行其功能,簡化開發。但是,也有一個壞處,就是一個虛函數,一旦被繼承類實現了,則父類的必然被覆蓋,如果父類有什么內置的功能,就沒有辦法執行了,這很麻煩,由于面向對象的繼承關系,我們總是希望,繼承類的對應函數,只要完成它相對于父類增加的那部分功能就夠了,父類的功能,還能繼續執行,免得寫重復的代碼。問題1: 當我聲明兩個全是虛函數時 結果也是 4答:對象里存的是“表”的地址。而非表。所以和幾個虛函數無關,就4個字節,如下例#include <iostream>using namespace std;class A public: virtual void f
9、un1() cout<<"fun1() called!"<<endl; virtual void fun3() cout<<"fun3() called!"<<endl; void fun2() cout<<"fun2() called!"<<endl; ;class B:public virtual A;class C:public virtual B;int main() cout<<sizeof(A)<<endl; cout<&
10、lt;sizeof(B)<<endl; cout<<sizeof(C)<<endl; return 0;輸入4 8 12,雖然A中有2個虛函數,由于只需保存虛表地址,所以認為4#include <iostream>using namespace std;class basepublic:virtual void fun1()cout << "fun1 called !" << endl;void fun2()cout << "fun2 called !" <<
11、 endl;double d;static int a;int main() base s; cout << sizeof(s) << endl; return 0;疑問 1: double 是8個字節 這個程序運行是16個字節 除了虛函數的4個 那多余處理的4個呢?疑問 2: static int a;我將static int 換成double是24個沒錯,可我將st
12、atic 去掉,那么個int應該是4個字節 共 4+8+4=16 可程序運行是24個 why?疑問 2:將static去掉后,然后int a和double d調換后還是24個字節,好像不符合內存對齊啊?答1:由于sizeof不能計算全局變量(static)和動態申請內存(malloc)的大小,只能計算局部變量(棧內存),所以static int a是不會計算字節大小的,由于內存對齊,double d占8個,虛表地址占8個,就共16個。參考程序員面試寶典二P57和P252的筆記答2:在類定義時,分配內存空間存在“字節對齊”的問題。編譯器首先根據類成員變量中所占空間的最大值(
13、如double為8個字節),每次都一次性分配這么大的空間,然后填充,因此可能會有剩余。去掉static的情況,共為24個字節,分析如下:1.類數據成員所需最大的空間為sizeof(double)=8字節2.編譯器首先分配8個字節給虛表指針3.編譯器接著分配8個字節給double d,雖然前面虛表指針只占4個字節,還剩下4個字節,但是不夠double所需的空間,因此需要重新分配8個字節4.編譯器最后分配8個字節給int a。編譯器進行”字節對齊“的一個重要的原因是便于類成員通過地址進行訪問答3:調換后不能節省8個字節空間。因為還有一條原則:虛表指針和其他的類成員不能共享一份內存空間,因此還是24
14、個字節。下面再舉一個例子:Class X1 virtual int disp(); int var1; double a;sizeof(X1)=24字節Class X2 virtual int disp(); int var1; int var2; double a;sizeof(X2)=24字節X1和X2類的大小(sizeof)相同,是因為虛表指針都“獨享”了一份內存空間(sizeof(double),而X2中var1和var2“共享”了一份內存空間。還有那個空類的大小為1,我感覺是分配一個字節給空類,在內存中給這個空類做一個標識,同時使這個空類的對象均指向同一個地址。我
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 莫西菌素在養殖業中的應用與研究綜述
- 承接汽車租賃合同協議書
- 創業計劃書(辣美美麻辣燙)
- 草地買賣合同協議書
- 2025年聚脲市場調研報告
- 藝術課堂創業項目計劃書
- 收購合同怎么寫協議書
- 廠房購買合同協議書樣本
- 2025年智能攝像頭的圖像識別與智能分析技術研究報告
- 2025年度節能真空泵項目可行性研究報告
- 2024-2025學年人教版數學六年級下學期期末試卷(含答案)
- 【MOOC期末】《模擬電子線路A》(南京郵電大學)期末中國大學慕課答案
- 2022-2023年湖南省普通高中學業水平合格考試英語真題試卷 含詳解
- 裝飾裝修三級安全教育培訓考試
- 船舶應急部署表及船員應變卡
- 爾雅《尊重學術道德遵守學術規范》期末考試答案0001
- 關聯交易模板詳解
- 政治經濟學計算題附答案
- 熱風爐烘爐方案2014.
- 人教版數學四年級下冊7、8、9單元綜合測試卷
- 牛津譯林版新教材高中英語選擇性必修一全冊課文原文
評論
0/150
提交評論