?? 深度探索c++對(duì)象模型(7).txt
字號(hào):
關(guān)于《深度探索C++對(duì)象模型》停頓了半個(gè)月,今天繼續(xù)啃這個(gè)骨頭,我的學(xué)習(xí)進(jìn)入了第四章,函數(shù)的語意學(xué)。先做個(gè)復(fù)習(xí)C++支持三種成員函數(shù):靜態(tài)、虛、和非靜態(tài)。每一種函數(shù)的調(diào)用方式都不同,當(dāng)然他們的作用也會(huì)有區(qū)別,一般來說我們只要掌握根據(jù)我們的需要正確的使用這三種類型的成員函數(shù)便可以了,至于內(nèi)部是如何運(yùn)做的我們可以不知。但是《深度探索C++對(duì)象模型》正是讓我們對(duì)這些不知道的東西進(jìn)行深度探索的一本書。通過前面的學(xué)習(xí),我想我知道了一些以前不知道的東西,但是感覺并沒有提高多少,也許是我對(duì)此書的學(xué)習(xí)還停留在一個(gè)比較膚淺的層次上吧。我想我應(yīng)該會(huì)抽時(shí)間再看幾遍。有些跑題了,因?yàn)槔咨裣胝f明一下,這些筆記只是雷神看書是的一些想法的記錄,如果你再看僅供參考,因?yàn)槲冶救撕孟笠仓惶剿髁瞬皇呛苌畹某潭取?我們的在設(shè)計(jì)和使用類時(shí)最常用的便是非靜態(tài)成員函數(shù),使用成員函數(shù)是為了封裝和隱藏我們的數(shù)據(jù),我想這是成員函數(shù)和外部函數(shù)的最明顯的區(qū)別。但是他們的效率是否有不同呢?我們不會(huì)想為了保護(hù)我們的數(shù)據(jù)而使用成員函數(shù),最后確導(dǎo)致效率降低的結(jié)果。讓我們看看非靜態(tài)成員函數(shù)在實(shí)際的執(zhí)行時(shí)被編譯器搞成了什么樣子。
float magnitude3d(const Point3d *_this){…}
//這是一個(gè)外部函數(shù),它有參數(shù)。表示它間接的取得坐標(biāo)(Point3d)成員。
float Point3d::mangnitude3d() const {…}
//這是一個(gè)成員函數(shù),它直接取得坐標(biāo)(Point3d)的成員。
表面上看,似乎成員函數(shù)的效率高很多,但實(shí)際上他們的效率真的想我們想象的那樣嗎?非也。實(shí)際上一個(gè)成員函數(shù)被內(nèi)部轉(zhuǎn)化成了外部函數(shù)。
1、 一個(gè)this指針被加入到成員函數(shù)的參數(shù)中,為的是能夠使類的對(duì)象調(diào)用這個(gè)函數(shù)。
2、 將對(duì)所有非靜態(tài)數(shù)據(jù)成員的存取操作改為由this來存取。
3、 對(duì)函數(shù)的名稱進(jìn)行重新的處理,使它成為程序中獨(dú)一無二的。
這時(shí)后,經(jīng)過以上的轉(zhuǎn)換,成員函數(shù)已經(jīng)成為了非成員函數(shù)。
float Point3d::mangnitude3d() const {…}//成員函數(shù)將被變成下面的樣子
//偽碼
mangnitude3d__7Point3dFv(register Point3d * const this)
{
return sqrt(this->_x * this->x+
this->_y * this->y+
this->_z * this->z);
}
調(diào)用此函數(shù)的操作也被轉(zhuǎn)換
obj. mangnitude3d()
被轉(zhuǎn)換成:
mangnitude3d__7Point3dFv(*obj);
怎么樣看出來了吧,和我們開始聲明的非成員函數(shù)沒有區(qū)別了。因此得出結(jié)論:兩個(gè)鐵球同時(shí)落地。
一般來說,一個(gè)成員的名稱前面會(huì)被加上類的名稱,形成唯一的命名。實(shí)際上在對(duì)成員名稱做處理時(shí),除了加上了類名,還會(huì)將參數(shù)的鏈表一并加上,這樣才能保證結(jié)果是獨(dú)一無二的。
我們?cè)趤砜纯挫o態(tài)成員函數(shù)。我們有這樣的概念,成員函數(shù)的調(diào)用必須是用類的對(duì)象,象這樣obj.fun();或者這樣ptr->fun().但實(shí)際上,只有一個(gè)或多個(gè)靜態(tài)數(shù)據(jù)成員被成員函數(shù)存取時(shí)才需要類的對(duì)象。類的對(duì)象提供一個(gè)指針this,用來將用到的非靜態(tài)數(shù)據(jù)成員綁定到類對(duì)象對(duì)應(yīng)的成員上。如果沒有用到任何一個(gè)成員數(shù)據(jù),就不需要用到this指針,也就沒有必要通過類的對(duì)象來調(diào)用一個(gè)成員函數(shù)。而且我們還知道靜態(tài)數(shù)據(jù)成員是在類之外的,可以被視做全局變量的,只不過它只在一個(gè)類的生命范圍內(nèi)可見。(參考前面的筆記)。而且一般來說我們會(huì)將靜態(tài)的數(shù)據(jù)成員聲明為一個(gè)非Public。這樣我們便必須提供一個(gè)或多個(gè)成員函數(shù)用來存取這個(gè)成員。雖然我們可以不依靠類的對(duì)象存取靜態(tài)數(shù)據(jù)成員,但是這個(gè)可以用來存取靜態(tài)成員的函數(shù)確實(shí)必須綁定在類的對(duì)象上的。為了更加好的解決這個(gè)問題,cfront2.0引入了靜態(tài)成員函數(shù)的概念。
靜態(tài)成員函數(shù)是沒有this指針的。因?yàn)樗恍枰ㄟ^類的對(duì)象來調(diào)用。而且它不能直接存取類中的非靜態(tài)成員。并且不能夠被聲明為virtual,const,volatile.如果取得一個(gè)靜態(tài)成員函數(shù)的地址,那么我們獲得的是這個(gè)函數(shù)在內(nèi)存中的位置。(非靜態(tài)成員函數(shù)的地址我們獲得的是一個(gè)指向這個(gè)類成員函數(shù)的指針,函數(shù)指針)。可以看到由于靜態(tài)成員函數(shù)沒有this指針,和非成員函數(shù)非常的相似。
有了前面幾章的基礎(chǔ),好象這些描述理解起來也不很費(fèi)勁,而且我們的思路可以跟著書上所說的一路傾瀉下來,這便是讀書的樂趣所在了,如果一本書讀起來都想讀第一章時(shí)那樣費(fèi)勁,我想我讀不下去的可能性會(huì)很高。
繼續(xù)我們的學(xué)習(xí),下面書上開始將虛函數(shù)了。我們知道虛函數(shù)是C++的一個(gè)很重要的特性,面向?qū)ο蟮亩鄳B(tài)便是由虛函數(shù)實(shí)現(xiàn)的。多態(tài)的概念是一個(gè)用一個(gè)public base class的指針(或者引用),尋址出一個(gè)派生類對(duì)象。虛函數(shù)實(shí)現(xiàn)的模型是這樣。每一個(gè)類都有一個(gè)虛函數(shù)表,它包含類中有作用的虛函數(shù)的地址,當(dāng)類產(chǎn)生對(duì)象時(shí)會(huì)有一個(gè)指針,指向虛函數(shù)表。為了支持虛函數(shù)的機(jī)制,便有了“執(zhí)行期多態(tài)”的形式。
下面這樣。
我們可以定義一個(gè)基類的指針。
Point *ptr;
然后在執(zhí)行期使他尋址出我們需要的對(duì)象。可以是
ptr =new Point2d;
還可以是
ptr=new Pont3d;
ptr這個(gè)指針負(fù)責(zé)使程序在任何地方都可以采用一組由基類派生的類型。這種多態(tài)形式是消極的,因?yàn)樗仨氃诰幾g時(shí)期完成。與之對(duì)應(yīng)的是一種多態(tài)的積極形式,即在執(zhí)行期完成用指針或引用查找我們的一個(gè)派生類的對(duì)象。
象下面這樣:
ptr->z();
要想達(dá)到我們目的,這個(gè)函數(shù)z()應(yīng)該是虛函數(shù),并且還應(yīng)該知道ptr所指的對(duì)象的真實(shí)類型,以便我們選擇z()的實(shí)體。以及z()實(shí)體的位置,以便我們能夠調(diào)用它。這些工作編譯器都會(huì)為我們做好,編譯器是如何做的呢?
我們已知每一個(gè)類會(huì)有一個(gè)虛函數(shù)表,這個(gè)表中含有對(duì)應(yīng)類的對(duì)象的所有虛函數(shù)實(shí)體的地址,并且可能會(huì)改寫一個(gè)基類的虛函數(shù)實(shí)體。如果沒有改寫基類存在的虛函數(shù)實(shí)體,則會(huì)繼承基類的函數(shù)實(shí)體,這還沒完,還會(huì)有一個(gè)pure_virtual_called()的函數(shù)實(shí)體。每一個(gè)虛函數(shù)不論是繼承的還是改寫的,都會(huì)被指派一個(gè)固定的索引值,這個(gè)索引在整個(gè)繼承體系中保持與特定的虛函數(shù)關(guān)聯(lián)。
說明:當(dāng)沒有改寫基類的虛函數(shù)時(shí),該函數(shù)的實(shí)體地址是被拷貝到派生類的虛函數(shù)表中的。
這樣我們便實(shí)現(xiàn)了執(zhí)行期的積極多態(tài)。這種形式的特點(diǎn)是,我們從頭到尾都不知道ptr指針指向了那一個(gè)對(duì)象類型,基類?派生類1?派生類2?我們不知道,也不需要知道。我們只需要知道ptr指向的虛函數(shù)表。而且我們也不知道z()函數(shù)的實(shí)體會(huì)被調(diào)用,我們只知道z()函數(shù)的函數(shù)地址被放在虛函數(shù)表中的位置。
總結(jié):在單一繼承的體系中,虛函數(shù)機(jī)制是一種很有效率的機(jī)制。我們判斷一個(gè)類是否支持多態(tài),只需要看它有沒有虛函數(shù)便可以了。 好了今天就到這里,雷神必須加快學(xué)習(xí)這本書的速度了,好象現(xiàn)在也可以快一些了。
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -