引用:
說明:使用虛函式,系統會有一定的空間開銷。當乙個類帶有虛函式時,編譯系統會為該類構造乙個虛函式表(位於類內其他成員前面),是乙個指標陣列,存放每個虛函式的入口位址。系統在進行動態關聯的時間開銷很少,提高了多型性的效率。
編譯器生成的析構函式都是非虛的,除非是乙個子類,其父類有個虛析構函式,此時的虛函式特性繼承自基類。有虛函式的類,一般情況下要定義乙個虛析構函式。
純虛函式不能new。
建構函式不能宣告為虛函式的原因?
什麼情況下,類的析構函式應該宣告為虛函式?為什麼?類a中有了虛函式就會再類的資料成員的最前面新增乙個vfptr指標(void** vfptr),這個指標用來指向乙個vtable表(乙個函式指標陣列)(乙個類只有乙個該錶),該錶儲存著當前類的所有 虛函式 的位址。這樣vfptr就成為了乙個類似成員變數的存在。訪問虛函式的時候通過vfptr間址找到vtable表,再間址進而找到要呼叫的函式。這樣就在一定程度上擺脫了型別制約。
當b類繼承a類的時候,因為a中有虛函式,編譯器就自動的給b類新增vfprt指標和vtable表。也可以理解為b類繼承來了a類中的那個vptr指標成員。(b物件的vfptr淺拷貝到a物件的vfptr)因此,a物件的vfptr所指向的是b物件的虛函式表,而b的析構函式位於書函式表0的位置,因此,這樣就可以通過a類物件的指標d,找到b類物件的析構函式,從而在delete d;時,可以銷毀b物件,而不會產生記憶體洩漏和異常。
# bug復現
a* aa= new b(); // b繼承a
delete aa;
// 列印(執行) a 的析構函式,不執行b的
所以需要將基類的析構函式宣告為虛函式,當撤銷基類物件的同時也撤銷派生類的物件,這個過程是動態關聯完成的。
內聯函式不能是虛函式內聯函式會在預編譯時會進行**展開,省略函式呼叫,因此內聯函式不能是虛函式。雖然使用inline和virtual共同修飾乙個函式時能夠通過編譯,並在呼叫時會表現出虛函式的性質,但這是因為編譯器在函式宣告中遇到virtual關鍵字時,會選擇忽略inline關鍵字,不進行**展開。
靜態函式不能宣告為虛函式虛函式體現了物件在執行時的多型性,而靜態函式屬於整個類,不屬於某個物件,不能宣告為虛函式。
建構函式 析構函式 虛析構函式
說析構函式之前,先說下建構函式。建構函式用來完成對物件的一系列初始化操作,主要作用有 1.給建立的物件建立乙個識別符號 2.為物件資料成員開闢記憶體空間 3.完成物件資料成員的初始化 當並未顯示的定義建構函式時,會生成乙個預設的建構函式,預設建構函式不能完成物件資料成員的初始化,只能給物件建立一識別...
建構函式不能為虛函式,析構函式要為虛函式
1,從儲存空間角度 虛函式對應乙個vtable,這大家都知道,可是這個vtable其實是儲存在物件的記憶體空間的。問題出來了,如果建構函式是虛的,就需要通過 vtable來呼叫,可是物件還沒有例項化,也就是記憶體空間還沒有,無法找到vtable,所以建構函式不能是虛函式。2,從使用角度 虛函式主要用...
C 析構函式 虛析構函式
1.為什麼要定義虛析構函式?如果有乙個帶有虛函式功能的類,則它需要乙個虛析構函式,原因如下 1 如果乙個類有虛函式功能,它經常作為乙個基類使用 2 如果它是乙個基類,它的派生類經常使用new來分配 3 如果乙個派生類物件使用new來分配,並且通過乙個指向它的基類的指標來控制,那麼它經常通過乙個指向它...