新聞中心
內(nèi)存模型描述的是程序中各變量(實(shí)例域、靜態(tài)域和數(shù)組元素)之間的關(guān)系,以及在實(shí)際計(jì)算機(jī)系統(tǒng)中將變量存儲(chǔ)到內(nèi)存和從內(nèi)存取出變量這樣的低層細(xì)節(jié).不同平臺(tái)間的處理器架構(gòu)將直接影響內(nèi)存模型的結(jié)構(gòu).

創(chuàng)新互聯(lián)公司專注于網(wǎng)站建設(shè)|成都網(wǎng)站維護(hù)公司|優(yōu)化|托管以及網(wǎng)絡(luò)推廣,積累了大量的網(wǎng)站設(shè)計(jì)與制作經(jīng)驗(yàn),為許多企業(yè)提供了網(wǎng)站定制設(shè)計(jì)服務(wù),案例作品覆蓋木屋等行業(yè)。能根據(jù)企業(yè)所處的行業(yè)與銷售的產(chǎn)品,結(jié)合品牌形象的塑造,量身制作品質(zhì)網(wǎng)站。
首先介紹一下C++中有繼承關(guān)系的類對(duì)象內(nèi)存的布局:
在C++中,如果類中有虛函數(shù),那么它就會(huì)有一個(gè)虛函數(shù)表的指針__vfptr,在類對(duì)象最開(kāi)始的內(nèi)存數(shù)據(jù)中。之后是類中的成員變量的內(nèi)存數(shù)據(jù)。
對(duì)于子類,最開(kāi)始的內(nèi)存數(shù)據(jù)記錄著父類對(duì)象的拷貝(包括父類虛函數(shù)表指針和成員變量)。之后是子類自己的成員變量數(shù)據(jù)。
對(duì)于子類的子類,也是同樣的原理。但是無(wú)論繼承了多少個(gè)子類,對(duì)象中始終只有一個(gè)虛函數(shù)表指針。
為了探討C++類對(duì)象的內(nèi)存布局,先來(lái)寫(xiě)幾個(gè)類和函數(shù)
首先寫(xiě)一個(gè)基類:
- class Base
- {
- public:
- virtual void f() { cout << "Base::f" << endl; }
- virtual void g() { cout << "Base::g" << endl; }
- virtual void h() { cout << "Base::h" << endl; }
- int base;
- protected:
- private:
- };
然后,我們多種不同的繼承情況來(lái)研究子類的內(nèi)存對(duì)象結(jié)構(gòu)。
1. 無(wú)虛函數(shù)集繼承
- //子類1,無(wú)虛函數(shù)重載
- class Child1 : public Base
- {
- public:
- virtual void f1() { cout << "Child1::f1" << endl; }
- virtual void g1() { cout << "Child1::g1" << endl; }
- virtual void h1() { cout << "Child1::h1" << endl; }
- int child1;
- protected:
- private:
- };
這個(gè)子類Child1沒(méi)有繼承任何一個(gè)基類的虛函數(shù),因此它的虛函數(shù)表如下圖:
我們可以看出,子類的虛函數(shù)表中,先存放基類的虛函數(shù),在存放子類自己的虛函數(shù)。
2. 有一個(gè)虛函數(shù)繼承
- //子類2,有1個(gè)虛函數(shù)重載
- class Child2 : public Base
- {
- public:
- virtual void f() { cout << "Child2::f" << endl; }
- virtual void g2() { cout << "Child2::g2" << endl; }
- virtual void h2() { cout << "Child2::h2" << endl; }
- int child2;
- protected:
- private:
- };
當(dāng)子類重載了父類的虛函數(shù),則編譯器會(huì)將子類虛函數(shù)表中對(duì)應(yīng)的父類的虛函數(shù)替換成子類的函數(shù)。
3. 全部虛函數(shù)都繼承
- //子類3,全部虛函數(shù)重載
- class Child3 : public Base
- {
- public:
- virtual void f() { cout << "Child3::f" << endl; }
- virtual void g() { cout << "Child3::g" << endl; }
- virtual void h() { cout << "Child3::h" << endl; }
- protected:
- int x;
- private:
- };
#p#
4. 多重繼承
多重繼承,即類有多個(gè)父類,這種情況下的子類的內(nèi)存結(jié)構(gòu)和單一繼承有所不同。
我們可以看到,當(dāng)子類繼承了多個(gè)父類,那么子類的內(nèi)存結(jié)構(gòu)是這樣的:
子類的內(nèi)存中,順序
5. 菱形繼承
6. 單一虛擬繼承
虛擬繼承的子類的內(nèi)存結(jié)構(gòu),和普通繼承完全不同。虛擬繼承的子類,有單獨(dú)的虛函數(shù)表, 另外也單獨(dú)保存一份父類的虛函數(shù)表,兩部分之間用一個(gè)四個(gè)字節(jié)的0x00000000來(lái)作為分界。子類的內(nèi)存中,首先是自己的虛函數(shù)表,然后是子類的數(shù)據(jù)成員,然后是0x0,之后就是父類的虛函數(shù)表,之后是父類的數(shù)據(jù)成員。
如果子類沒(méi)有自己的虛函數(shù),那么子類就不會(huì)有虛函數(shù)表,但是子類數(shù)據(jù)和父類數(shù)據(jù)之間,還是需要0x0來(lái)間隔。
因此,在虛擬繼承中,子類和父類的數(shù)據(jù),是完全間隔的,先存放子類自己的虛函數(shù)表和數(shù)據(jù),中間以0x分界,最后保存父類的虛函數(shù)和數(shù)據(jù)。如果子類重載了父類的虛函數(shù),那么則將子類內(nèi)存中父類虛函數(shù)表的相應(yīng)函數(shù)替換。
7. 菱形虛擬繼承
結(jié)論:
(1) 對(duì)于基類,如果有虛函數(shù),那么先存放虛函數(shù)表指針,然后存放自己的數(shù)據(jù)成員;如果沒(méi)有虛函數(shù),那么直接存放數(shù)據(jù)成員。
(2) 對(duì)于單一繼承的類對(duì)象,先存放父類的數(shù)據(jù)拷貝(包括虛函數(shù)表指針),然后是本類的數(shù)據(jù)。
(3) 虛函數(shù)表中,先存放父類的虛函數(shù),再存放子類的虛函數(shù)
(4) 如果重載了父類的某些虛函數(shù),那么新的虛函數(shù)將虛函數(shù)表中父類的這些虛函數(shù)覆蓋。
(5) 對(duì)于多重繼承,先存放第一個(gè)父類的數(shù)據(jù)拷貝,在存放第二個(gè)父類的數(shù)據(jù)拷貝,一次類推,最后存放自己的數(shù)據(jù)成員。其中每一個(gè)父類拷貝都包含一個(gè)虛函數(shù)表指針。如果子類重載了某個(gè)父類的某個(gè)虛函數(shù),那么該將該父類虛函數(shù)表的函數(shù)覆蓋。另外,子類自己的虛函數(shù),存儲(chǔ)于第一個(gè)父類的虛函數(shù)表后邊部分。
(6) 當(dāng)對(duì)象的虛函數(shù)被調(diào)用是,編譯器去查詢對(duì)象的虛函數(shù)表,找到該函數(shù),然后調(diào)用。
到這c++類對(duì)象的內(nèi)存模型就介紹完了,希望對(duì)大家有幫助。
【編輯推薦】
- 使用托管C++粘合C#和C++代碼(一)
- 談?wù)凜++中三個(gè)容易混淆的概念
- C/C++是程序員必須掌握的語(yǔ)言嗎?
- VC++獲得當(dāng)前系統(tǒng)時(shí)間的幾種方案
- C++連接mysql數(shù)據(jù)庫(kù)的兩種方法
當(dāng)前名稱:詳細(xì)介紹c++中的類對(duì)象內(nèi)存模型
網(wǎng)站鏈接:http://m.5511xx.com/article/dpdodji.html


咨詢
建站咨詢
