C 記憶體中的封裝 繼承 多型(上)

2022-03-12 02:40:40 字數 3728 閱讀 5283

此篇我們從c++物件記憶體布局和構造過程來具體分析c++中的封裝、繼承、多型。

一、封裝模型的記憶體布局

常見類物件的成員可能包含以下元素:內建型別、指標、引用、組合物件、虛函式。

另乙個角度的分類:

資料成員:靜態、非靜態

成員函式:靜態、非靜態、虛函式

1.僅包含內建型別的場合:

class

t;

類中的內建型別按照宣告的順序在記憶體中連續儲存,並且分配的大小由內建型別本身的大小決定(依賴機器),布局受位元組對齊影響(本篇不討論位元組對齊)

2.包含指標和引用的場合:

class

t;

儲存方式同1的場合,不同點為指標和引用通常為固定大小(32位機器4位元組、64位機器8位元組)。有關引用:個人理解的引用就是懶人專用指標,取位址又間位址是很麻煩的操作,於是出現了自動取址又間址的指向常量的常指標

在類中宣告可以測出固定位元組大小,所以也是占用固定的位元組大小。

3.包含組合物件的場合:

classq;

class

t;

記憶體布局圖示(本篇以及後續篇使用的環境為 32位win7, vs2008):

結論:(顯而易見就不解釋了)

類物件最終被解釋成內建型別,布局依然按照宣告的順序,並且物件布局在記憶體中依然是連續的

4.在3的場合新增虛函式的場合

class

q

inta;

intb;

};class

t

intdata1;

q q;

double

data2;

};

記憶體布局圖示

通過程式輸出看一下

typedef void (*pf)();

intmain()

輸出圖示

推理證明:

1.取t的位址強轉成(int*)型別輸出以後得到的位址 == 取t的vfptr的位址(除錯視窗第一行):虛函式指標被放在物件布局的首位址位置

2.因為(int*)&t == vfptr,那麼*vfptr得到的是虛函式表的首位址。

(int*)*vfptr,把虛函式表的首位址強轉成(int*)的位址 == t物件的__vftable的虛函式表的位址(除錯視窗第四行行):虛函式指標指向虛函式表

3.vftable的首位址到vftable的第乙個函式的位址中間相差很多空間:虛函式表還承擔了虛函式以外的內容

什麼內容也會放在虛函式表中呢?

結論:

在包含虛函式的場合多了乙個vfptr,它是乙個const指標,位於類布局中的首位置,指向了虛函式表,虛函式表包含了虛函式位址,通過虛函式位址訪問虛函式。

並且虛函式表的首位址存在了本類的型別資訊,用於實現rtti。

5.包含了static的場合

static的特性眾所周知,從除錯視窗觀察變數並不能得出什麼結論,我們先列出幾條特性:

1.static成員為整個類共有的屬性

2.static函式不包含this指標

3.static成員不能訪問nonstatic成員

初步結論:

記憶體物件模型中對static作了隔離處理(不是所有物件具有的),static自己獨霸一方。

通過以上5條現在來構建c++的封裝模型:

有關普通的成員函式

所謂類,就是自己圈定了乙個網域名稱,所以在記憶體中的**區也圈定了自己的域,普通的成員函式放在那裡。

有關靜態成員函式

在**區中圈定的類網域名稱中的圈定乙個static區域,思路依然是獨霸一方。

有關建構函式

由於建構函式的特殊性,所以在**區擁有乙個自己的構造**區域。

現在又有了乙個更完整的模型:

假定讀者已經了解堆/棧/靜態區和常量區/**區

根據上圖我們得到一些結論

1.類最終被解釋內建型別(內建型別過了編譯期以後,都不復存在,只是編譯期的解讀方式而已)

2.內建型別按照宣告的次序順序儲存

3.存在虛函式的場合,會生成vfptr,並且vfptr->vtable->function()

4.靜態成員被單獨對待、資料只有乙份拷貝,函式被放到static區域。

5.type infomation被放到vftable中

二、封裝模型的構造過程

1.靜態是編譯期決定的,所有物件共有的資料拷貝,優先建立。

2.進入建構函式,優先建立vfptr和vftable,也就是優先構造虛函式部分

3.其次按照宣告的順序構造資料成員。

我們可以使用逗號表示式來幹一些有意思的事情。

事先我們需要定義

typedef void (*pf)();

pf pf = null;

class

q//組合物件的初始化順序,注意初始化列表寫的順序是和宣告的順序相反的

virtual

void fun()

inta;

intb;

};class

t//data2的構造使用了簡單的逗號表示式

//data1的初始化巢狀了一層逗號表示式,結構其實是data1((為函式指標pf賦值, 呼叫pf), 列印data1構造中, 數值)

virtual

void fun()

intdata1;

q q;

double

data2;

static

intsdata1;

};int t::sdata1 = (cout<

sdata1 constructing\n

", 10);//用來指定靜態變數的初始化順序

以下是程式執行的結果:

靜態--虛函式表--宣告次序初始化。

c 封裝,繼承,多型

一 封裝 封裝是實現物件導向程式設計的第一步,封裝就是將資料或函式等集合在乙個個的單元中 我們稱之為類 被封裝的物件通常被稱為抽象資料型別。物件導向程式設計中一般以類作為資料封裝的基本單位。類將資料和運算元據的方法結合成乙個單位。在設計類時,不希望直接訪問類中的資料,而是希望通過方法來訪問資料。如此...

C 封裝 繼承 多型

物件導向的三個基本特徵 物件導向的三個基本特徵是 封裝 繼承 多型。其中,封裝可以隱藏實現細節,使得 模組化 繼承可以擴充套件已存在的 模組 類 它們的目的都是為了 重用。而多型則是為了實現另乙個目的 介面重用!封裝 什麼是封裝?封裝可以隱藏實現細節,使得 模組化 封裝是把過程和資料報圍起來,對資料...

c 封裝,繼承,多型

c 中可使用類來達到資料封裝的效果,這樣可以使資料與方法封裝成單一元素,以便於通過方法訪問資料。除此之外,還可以控制資料的訪問方式。在物件導向程式設計中,大多數都是以類作為資料封裝的基本單位。類將資料和運算元據的方法結合成乙個單位。設計類時,不希望直接訪問類中的資料,而是希望通過方法來訪問資料。這樣...