c++ 多態(tài) 虛函數(shù) 析構(gòu)函數(shù) 抽象類

1. 析構(gòu)函數(shù)和虛析構(gòu)函數(shù)

如果基類的析構(gòu)函數(shù)是虛的丽惶,那么它的派生類的析構(gòu)函數(shù)都是虛的

這將導致:當派生類析構(gòu)的時候音羞,它的所有的基類的析構(gòu)函數(shù)都將得到調(diào)用

否則仓犬,只調(diào)用派生類的析構(gòu)函數(shù)(這可能導致基類的某些對象沒有得到釋放)

所以CObject類的析構(gòu)函數(shù)是虛的搀继,所有由它派生的類析構(gòu)的時候一級一級的進行,不會造成內(nèi)存泄漏财边。

??? 無論基類的析構(gòu)函數(shù)是否為虛析構(gòu)函數(shù). 基類的析構(gòu)函數(shù)總是會被自動調(diào)用的;但是, 如果用基類指針去操作一個了派生類對象,如果不為虛就不能保證派生類的析構(gòu)函數(shù)被調(diào)用酣难。

總結(jié)一下虛析構(gòu)函數(shù)的作用:

(1)如果父類的析構(gòu)函數(shù)不加virtual關鍵字

當父類的析構(gòu)函數(shù)不聲明成虛析構(gòu)函數(shù)的時候憨募,當子類繼承父類袁辈,父類的指針指向子類時晚缩,delete掉父類的指針(也就是析構(gòu)函數(shù)里面的 deletel baseptr)荞彼,只調(diào)動父類的析構(gòu)函數(shù),而不調(diào)動子類的析構(gòu)函數(shù)(因為沒辦法去訪問派生類的成員函數(shù)莺债,只能訪問成員數(shù)據(jù)變量)。

(2)如果父類的析構(gòu)函數(shù)加virtual關鍵字

當父類的析構(gòu)函數(shù)聲明成虛析構(gòu)函數(shù)的時候椎侠,當子類繼承父類我纪,父類的指針指向子類時丐吓,delete掉父類的指針(也就是析構(gòu)函數(shù)里面的 deletel baseptr)券犁,先調(diào)動子類的析構(gòu)函數(shù)粘衬,再調(diào)動父類的析構(gòu)函數(shù)。 (構(gòu)造函數(shù)先調(diào)用父類再調(diào)用子類勘伺,析構(gòu)函數(shù)先調(diào)用子類再調(diào)用父類飞醉,即先構(gòu)造的后刪除

2. 純虛析構(gòu)函數(shù)

??? 析構(gòu)函數(shù)的純虛性唯一效果就是保證抽象類的實例化缅帘。

?? 《Effective C++》中第14條條款的一部分股毫,既是對虛析構(gòu)函數(shù)的徹底理解召衔,亦是對純虛析構(gòu)函數(shù)作用的解釋苍凛。

??? 在某些類里聲明純虛析構(gòu)函數(shù)很方便。純虛函數(shù)將產(chǎn)生抽象類——不能實例化的類(即不能創(chuàng)建此類型的對象)宣肚。有些時候霉涨,你想使一個類成為抽象類,但剛好又沒有任何純虛函數(shù)笙瑟。怎么辦?因為抽象類是準備被用做基類的框产,基類必須要有一個虛析構(gòu)函數(shù)秉宿,純虛函數(shù)會產(chǎn)生抽象類描睦,所以方法很簡單:在想要成為抽象類的類里聲明一個純虛析構(gòu)函數(shù)酌摇。

這里是一個例子:

class awov {

public:

virtual ~awov() = 0;????? // 聲明一個純虛析構(gòu)函數(shù)

};

????? 這個類有一個純虛函數(shù)嗡载,所以它是抽象的洼滚,而且它有一個虛析構(gòu)函數(shù)遥巴,所以不會產(chǎn)生析構(gòu)函數(shù)問題铲掐。但這里還有一件事:必須提供純虛析構(gòu)函數(shù)的定義:

awov::~awov() {}?????????? // 純虛析構(gòu)函數(shù)的定義

這個定義是必需的摆霉,因為虛析構(gòu)函數(shù)工作的方式是:最底層的派生類的析構(gòu)函數(shù)最先被調(diào)用携栋,然后各個基類的析構(gòu)函數(shù)被調(diào)用婉支。這就是說向挖,即使是抽象類,編譯器也要產(chǎn)生對~awov的調(diào)用跟畅,所以要保證為它提供函數(shù)體碍彭。如果不這么做庇忌,鏈接器就會檢測出來舰褪,最后還是得回去把它添上略就。

3. 虛函數(shù)

【1】在基類用virtual聲明成員函數(shù)為虛函數(shù)。這樣就可以在派生類中重新定義此函數(shù)表牢,為它賦予新的功能崔兴,并能方便地被調(diào)用。

【2】在派生類中重新定義此函數(shù)山析,要求函數(shù)名笋轨、函數(shù)(返回)類型、函數(shù)參數(shù)個數(shù)和類型與基函數(shù)的虛函數(shù)相同鸟款。如果在派生類中沒有對基類的虛函數(shù)重定義何什,則派生類簡單地繼承直接基類的虛函數(shù)处渣。

【3】C++規(guī)定罐栈,當一個成員函數(shù)被聲明為虛函數(shù)后,其派生類中的同名函數(shù)(符合2中定義的函數(shù))都自動成為虛函數(shù)荠诬。

【4】定義一個指向基類對象的指針變量琅翻,并使其指向同一類族中的某個對象锨天。通過該指針變量調(diào)用此函數(shù)杂伟,此時調(diào)用的就是指針變量指向的對象的同名函數(shù)。

【5】只能用virtual聲明類的成員函數(shù)拯钻,使它成為虛函數(shù)钧嘶,而不能將類外的普通函數(shù)聲明為虛函數(shù)棠众。

【6】一個成員函數(shù)被聲明為虛函數(shù)后,在同一類族中的類就不能再定義一個非virtual的但與該虛函數(shù)具有相同參數(shù)(個數(shù)與類型)和函數(shù)返回值類型的同名函數(shù)有决。

【7】靜態(tài)成員函數(shù)不能是虛函數(shù)闸拿,因為靜態(tài)成員函數(shù)不受限于某個對象。

【8】inline函數(shù)不能是虛函數(shù)书幕,因為inline函數(shù)是不能在運行中動態(tài)確定其位置的。即使虛函數(shù)在類的內(nèi)部定義,編譯時奔缠,仍將其視為非inline的。

【5】使用虛函數(shù),系統(tǒng)要有一定的空間開銷。當一個類帶有虛函數(shù)時测蘑,編譯器會為該類構(gòu)造一個虛函數(shù)表(virtual function tanle,vtable)沫勿,它是一個指針數(shù)組,存放每個虛函數(shù)的入口地址时甚。

4. 純虛函數(shù)

一個函數(shù)聲明為純虛后,純虛函數(shù)的意思是:我是一個抽象類!不要把我實例化!純虛函數(shù)用來規(guī)范派生類的行為又碌,實際上就是所謂的“接口”。它告訴使用者,我的派生類都會有這個函數(shù)。

virtual void show()=0;//純虛函數(shù)

這里將show()聲明為純虛函數(shù)(pure virtual function)墅拭。純虛函數(shù)是在聲明虛函數(shù)時被“初始化”為0的虛函數(shù)穗熬。

聲明純虛函數(shù)的一般形式為妓柜,

virtual 函數(shù)類型 函數(shù)名(參數(shù)列表)=0;

純虛函數(shù)沒有函數(shù)體作煌;最后的“=0”并不代表函數(shù)返回值為0鹰服,它只起形式上的作用笼踩,告訴編譯器“這是純虛函數(shù)”;這個一個聲明語句斑胜,最后有分號涧狮。

聲明純虛函數(shù)是告訴編譯器譬嚣,“在這里聲明了一個虛函數(shù),留待派生類中定義”。在派生類中對此函數(shù)提供了定義后泵督,它才能具備函數(shù)的功能,可以被調(diào)用。

純虛函數(shù)的作用是在基類中為其派生類保留了一個函數(shù)的名字,以便派生類根據(jù)需要對它進行定義。

如果在一個類中聲明了純虛函數(shù)租漂,而在其派生類中沒有對該函數(shù)定義,則該函數(shù)在派生類中仍為純虛函數(shù)。

1. 虛函數(shù)和純虛函數(shù)可以定義在同一個類(class)中骑脱,含有純虛函數(shù)的類被稱為抽象類(abstract class)苍糠,而只含有虛函數(shù)的類(class)不能被稱為抽象類(abstract class)叁丧。

2. 虛函數(shù)可以被直接使用,也可以被子類(sub class)重載以后以多態(tài)的形式調(diào)用岳瞭,而純虛函數(shù)必須在子類(sub class)中實現(xiàn)該函數(shù)才可以使用拥娄,因為純虛函數(shù)在基類(base class)

只有聲明而沒有定義。

?? 3. 虛函數(shù)和純虛函數(shù)都可以在子類(sub class)中被重載瞳筏,以多態(tài)的形式被調(diào)用稚瘾。

?? 4. 虛函數(shù)和純虛函數(shù)通常存在于抽象基類(abstract base class -ABC)之中,被繼承的子類重載乏矾,目的是提供一個統(tǒng)一的接口孟抗。

5. 虛函數(shù)的定義形式:virtual??? {method body}

純虛函數(shù)的定義形式:virtual??? { } = 0;

在虛函數(shù)和純虛函數(shù)的定義中不能有static標識符,原因很簡單钻心,被static修飾的函數(shù)在編譯時候要求前期bind,然而虛函數(shù)卻是動態(tài)綁定(run-time bind)凄硼,而且被兩者修飾的函數(shù)生命周期(life recycle)也不一樣。

6. 如果一個類中含有純虛函數(shù)捷沸,那么任何試圖對該類進行實例化的語句都將導致錯誤的產(chǎn)生摊沉,因為抽象基類(ABC)是不能被直接調(diào)用的。必須被子類繼承重載以后痒给,根據(jù)要求調(diào)用其子類的方法说墨。

5? 純抽象類

?? 從C++的 角度來看,一個抽象類和一個接口之間沒有任何區(qū)別苍柏。有時尼斧,我們習慣使用“純抽象類”這個詞來表示某個類僅僅只含有純虛函數(shù)(不包含任何數(shù)據(jù)成員),它是抽象類的最常見的形式试吁。

?? 使用純抽象類有什么好處棺棵?最明顯的例子就是“多接口、單實現(xiàn)”熄捍,這是一種很常見的情況烛恤。

?? 在C++中加入了 純虛函數(shù)的概念,一個純虛函數(shù)必須被其派生類重寫余耽。借助此概念缚柏,你可以在一個C++類中通過將其成員函數(shù) 聲明為純虛函數(shù)的方法表明該類是一個純接口類。從那以后碟贾,我就一直強調(diào)在C++中,有一種主要的使用類的方法就是讓該類不包含任何狀態(tài)粱锐, 而僅僅作為一個接口。

6? 抽象類

將不用來定義對象而只作為一種基本類型用作繼承的類恶座,稱為抽象類(abstract class),由于它常用作基類桂敛,通常稱為抽象基類术唬。凡是包含純虛函數(shù)的類都是抽象類粗仓。

如果在派生類中沒有對所有的純虛函數(shù)進行定義萝招,則此派生類仍然是抽象類橡淆,不能用來定義對象。

可以定義指向抽象類數(shù)據(jù)的指針變量师倔。當派生類成為具體類后凶朗,就可以用這個指針指向派生類對象搓萧,然后通過該指針調(diào)用虛函數(shù)。

??? 帶有純虛函數(shù)的類稱為抽象類。抽象類是一種特殊的類石蔗,它是為了抽象和設計的目的而建立的养距,它處于繼承層次結(jié)構(gòu)的較上層。抽象類是不能定義對象的,在實際中為了強調(diào)一個類是抽象類揣炕,可將該類的構(gòu)造函數(shù)說明為保護的訪問控制權(quán)限丁恭。抽象類的主要作用是將有關的組織在一個繼承層次結(jié)構(gòu)中,由它來為它們提供一個公共的根恶守,相關的子類是從這個根派生出來的第献。抽象類刻畫了一組子類的操作接口的通用語義,這些語義也傳給子類兔港。一般而言庸毫,抽象類只描述這組子類共同的操作接口,而完整的實現(xiàn)留給子類衫樊。抽象類只能作為基類來使用飒赃,其純虛函數(shù)的實現(xiàn)由派生類給出。如果派生類沒有重新定義純虛函數(shù)科侈,而派生類只是繼承基類的純虛函數(shù)盒揉,則這個派生類仍然還是一個抽象類。如果派生類中給出了基類純虛函數(shù)的實現(xiàn)兑徘,則該派生類就不再是抽象類了刚盈,它是一個可以建立對象的具體類了。

7 java 中的接口

不需要聲明接口為抽象或虛擬(本來就是)

接口不允許有構(gòu)造函數(shù)(純抽象了挂脑,根本不需要構(gòu)造)

接口不允許有析構(gòu)函數(shù)(本來無構(gòu)造藕漱,何需有析構(gòu))

接口的所有成員都是抽象的(純抽象類嘛)

接口只可以從接口繼承(因為只有接口可以保證使純虛的欲侮,如果從抽象類繼承,不能保證抽象類中可能存在非抽象的成員)

接口成員不允許有任何修飾(默認就是public的肋联,也只有是public的)

一個類或結(jié)構(gòu)可以實現(xiàn)多個接口

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末威蕉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子橄仍,更是在濱河造成了極大的恐慌韧涨,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侮繁,死亡現(xiàn)場離奇詭異虑粥,居然都是意外死亡,警方通過查閱死者的電腦和手機宪哩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門娩贷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人锁孟,你說我怎么就攤上這事彬祖。” “怎么了品抽?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵储笑,是天一觀的道長。 經(jīng)常有香客問我圆恤,道長南蓬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任哑了,我火速辦了婚禮赘方,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘弱左。我一直安慰自己窄陡,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布拆火。 她就那樣靜靜地躺著跳夭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪们镜。 梳的紋絲不亂的頭發(fā)上币叹,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音模狭,去河邊找鬼颈抚。 笑死,一個胖子當著我的面吹牛嚼鹉,可吹牛的內(nèi)容都是我干的贩汉。 我是一名探鬼主播驱富,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼匹舞!你這毒婦竟也來了褐鸥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赐稽,失蹤者是張志新(化名)和其女友劉穎叫榕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姊舵,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡晰绎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蠢莺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡零如,死狀恐怖躏将,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情考蕾,我是刑警寧澤祸憋,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站肖卧,受9級特大地震影響蚯窥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜塞帐,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一拦赠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧葵姥,春花似錦荷鼠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至削咆,卻和暖如春牍疏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拨齐。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工鳞陨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瞻惋。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓炊邦,卻偏偏與公主長得像编矾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子馁害,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容