C++成员函数在内存中的存储方式
用類去定義對象時,系統(tǒng)會為每一個對象分配存儲空間。如果一個類包括了數(shù)據(jù)和函數(shù),要分別為數(shù)據(jù)和函數(shù)的代碼分配存儲空間。按理說,如果用同一個類定義了10個對象,那么就需要分別為10個對象的數(shù)據(jù)和函數(shù)代碼分配存儲單元,如下圖所示。
?
能否只用一段空間來存放這個共同的函數(shù)代碼段,在調用各對象的函數(shù)時,都去調用這個公用的函數(shù)代碼。如下圖所示。
顯然,這樣做會大大節(jié)約存儲空間。C++編譯系統(tǒng)正是這樣做的,因此每個對象所占用的存儲空間只是該對象的數(shù)據(jù)部分(虛函數(shù)指針和虛基類指針也屬于數(shù)據(jù)部分)所占用的存儲空間,而不包括函數(shù)代碼所占用的存儲空間。
????????看如下測試代碼
class D { public: void printA() { cout<<"printA"<<endl; } virtual void printB() { cout<<"printB"<<endl; } }; int main(void) {D *d=NULL;d->printA();d->printB(); }問題:以上代碼的輸出結果是什么?
????????C++程序的內存格局通常分為四個區(qū):全局數(shù)據(jù)區(qū)(data area),代碼區(qū)(code area),棧區(qū)(stack area),堆區(qū)(heap area)(即自由存儲區(qū))。全局數(shù)據(jù)區(qū)存放全局變量,靜態(tài)數(shù)據(jù)和常量;所有類成員函數(shù)和非成員函數(shù)代碼存放在代碼區(qū);為運行函數(shù)而分配的局部變量、函數(shù)參數(shù)、返回數(shù)據(jù)、返回地址等存放在棧區(qū);余下的空間都被稱為堆區(qū)。根據(jù)這個解釋,我們可以得知在類的定義時,類成員函數(shù)是被放在代碼區(qū),而類的靜態(tài)成員變量在類定義時就已經在全局數(shù)據(jù)區(qū)分配了內存,因而它是屬于類的。對于非靜態(tài)成員變量,我們是在類的實例化過程中(構造對象)才在棧區(qū)或者堆區(qū)為其分配內存,是為每個對象生成一個拷貝,所以它是屬于對象的。
????????應當說明,常說的“某某對象的成員函數(shù)”,是從邏輯的角度而言的,而成員函數(shù)的存儲方式,是從物理的角度而言的,二者是不矛盾的。
????????下面我們再來討論下類的靜態(tài)成員函數(shù)和非靜態(tài)成員函數(shù)的區(qū)別:靜態(tài)成員函數(shù)和非靜態(tài)成員函數(shù)都是在類的定義時放在內存的代碼區(qū)的,因而可以說它們都是屬于類的,但是類為什么只能直接調用靜態(tài)類成員函數(shù),而非靜態(tài)類成員函數(shù)(即使函數(shù)沒有參數(shù))只有類對象才能調用呢?原因是類的非靜態(tài)類成員函數(shù)其實都內含了一個指向類對象的指針型參數(shù)(即this指針),因而只有類對象才能調用(此時this指針有實值)。
????????回答開頭的問題,答案是輸出“printA”后,程序崩潰。類中包括成員變量和成員函數(shù)。new出來的只是成員變量,成員函數(shù)始終存在,所以如果成員函數(shù)未使用任何成員變量的話,不管是不是static的,都能正常工作。需要注意的是,雖然調用不同對象的成員函數(shù)時都是執(zhí)行同一段函數(shù)代碼,但是執(zhí)行結果一般是不相同的。不同的對象使用的是同一個函數(shù)代碼段,它怎么能夠分別對不同對象中的數(shù)據(jù)進行操作呢?原來C++為此專門設立了一個名為this的指針,用來指向不同的對象。
????????需要說明,不論成員函數(shù)在類內定義還是在類外定義,成員函數(shù)的代碼段都用同一種方式存儲。不要將成員函數(shù)的這種存儲方式和inline(內聯(lián))函數(shù)的概念混淆。不要誤以為用inline聲明(或默認為inline)的成員函數(shù),其代碼段占用對象的存儲空間,而不用inline聲明的成員函數(shù),其代碼段不占用對象的存儲空間。不論是否用inline聲明(或默認為inline),成員函數(shù)的代碼段都不占用對象的存儲空間。用inline聲明的作用是在調用該函數(shù)時,將函數(shù)的代碼段復制插人到函數(shù)調用點,而若不用inline聲明,在調用該函數(shù)時,流程轉去函數(shù)代碼段的入口地址,在執(zhí)行完該函數(shù)代碼段后,流程返回函數(shù)調用點。inline與成員函數(shù)是否占用對象的存儲空間無關,它們不屬于同一個問題,不應搞混。
?
總結
以上是生活随笔為你收集整理的C++成员函数在内存中的存储方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为什么成员函数不占用类和对象的空间
- 下一篇: C++虚函数表,虚表指针,内存分布