Effective C++ 第七條 Declare destructors virtual in polymorphic bas

為多態(tài)基類(lèi)聲明virtual析構(gòu)函數(shù)
考慮一個(gè)情況,就是我們當(dāng)前有一個(gè)目標(biāo)功能,就是時(shí)間操作,但是有多種方法可以嘗試,比如原子鐘、水鐘、腕表等

注意,這里的析構(gòu)函數(shù)是non-virtual的,原則上來(lái)說(shuō)不適合作為基類(lèi)(base-class),不適合用于作為繼承的父類(lèi),原因需要考慮到以下場(chǎng)景

程序運(yùn)行也許不會(huì)出錯(cuò),但是有一些問(wèn)題會(huì)導(dǎo)致內(nèi)存泄漏,比如當(dāng)客戶(hù)使用完需要釋放空間的時(shí)候,delete ptr;并不難完全釋放空間,因?yàn)檫@里我們想使用類(lèi)的多態(tài)性質(zhì),通告一個(gè)TimeKeeper(base)去實(shí)現(xiàn)多種子類(lèi)(derived),然而TimeKeeper型指針在構(gòu)造的時(shí)候只會(huì)初始化屬于TimeKeeper的內(nèi)容,不會(huì)初始化AtomicClock里的成員(這一點(diǎn)暫且記住,不是本章重點(diǎn))。更重要的是,TimeKeeper的析構(gòu)函數(shù)并不會(huì)去釋放子類(lèi)中的空間,只會(huì)釋放屬于TimeKeeper類(lèi)中的 __i_T;管不了子類(lèi)中的 __i_AC;這一點(diǎn)可能導(dǎo)致很?chē)?yán)重的空間浪費(fèi)。于是我們采取父類(lèi)使用虛析構(gòu)函數(shù)(關(guān)于 vtbl 和 vptr 的詳細(xì)內(nèi)容放到本章末尾,如果不懂可以先看完末尾講解再回到當(dāng)前位置繼續(xù)閱讀)

采用了虛析構(gòu)函數(shù)之后,delete ptr;便會(huì)調(diào)用子類(lèi)的析構(gòu)函數(shù)了,便不需要擔(dān)心子類(lèi)的成員無(wú)法釋放。但是也不建議無(wú)腦用virtual,如果一個(gè)類(lèi)設(shè)計(jì)出來(lái)便是為了做父類(lèi)的就建議使用虛析構(gòu)函數(shù),因?yàn)槟忝渴褂靡粋€(gè)虛函數(shù)會(huì)多使用一個(gè)虛函數(shù)指針,每個(gè)指針占據(jù) 8 字節(jié)(在64位操作系統(tǒng)下),如果使用了很多虛函數(shù)但是卻沒(méi)有實(shí)際用處,會(huì)浪費(fèi)空間,不利于cache命中,降低程序運(yùn)行速度。
vptr 和 vtbl 的作用
virtual table pointer 和 virtual table 是為了實(shí)現(xiàn)多態(tài)而出現(xiàn)的,下面給出一個(gè)實(shí)例

此時(shí)輸出為 A A A ,a2和a3是B1和B2類(lèi),但是仍綁定的A的op
如果給A中的op加上virtual

此時(shí)輸出結(jié)果是 A B1 B2,也就是說(shuō)實(shí)現(xiàn)了多態(tài),這樣的好處是,用戶(hù)在使用功能的時(shí)候不需要區(qū)分清楚A、B1、B2的區(qū)別,我們可以把A看作初始版本,B1、B2看作迭代版本,無(wú)論版本迭代多少次,用戶(hù)只需要按照最初的操作即可完成任務(wù)。后續(xù)的布丁只需如此

