此篇我們從c++物件記憶體布局和構造過程來具體分析c++中的封裝、繼承、多型。
一、封裝模型的記憶體布局
常見類物件的成員可能包含以下元素:內建型別、指標、引用、組合物件、虛函式。
另乙個角度的分類:
資料成員:靜態、非靜態
成員函式:靜態、非靜態、虛函式
1.僅包含內建型別的場合:
class類中的內建型別按照宣告的順序在記憶體中連續儲存,並且分配的大小由內建型別本身的大小決定(依賴機器),布局受位元組對齊影響(本篇不討論位元組對齊)。t;
2.包含指標和引用的場合:
class儲存方式同1的場合,不同點為指標和引用通常為固定大小(32位機器4位元組、64位機器8位元組)。有關引用:個人理解的引用就是懶人專用指標,取位址又間位址是很麻煩的操作,於是出現了自動取址又間址的指向常量的常指標。t;
在類中宣告可以測出固定位元組大小,所以也是占用固定的位元組大小。
3.包含組合物件的場合:
classq;記憶體布局圖示(本篇以及後續篇使用的環境為 32位win7, vs2008):class
t;
結論:(顯而易見就不解釋了)
類物件最終被解釋成內建型別,布局依然按照宣告的順序,並且物件布局在記憶體中依然是連續的
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 中可使用類來達到資料封裝的效果,這樣可以使資料與方法封裝成單一元素,以便於通過方法訪問資料。除此之外,還可以控制資料的訪問方式。在物件導向程式設計中,大多數都是以類作為資料封裝的基本單位。類將資料和運算元據的方法結合成乙個單位。設計類時,不希望直接訪問類中的資料,而是希望通過方法來訪問資料。這樣...