C 知識點51 虛函式與純虛函式(下)

2021-10-10 17:58:57 字數 2780 閱讀 5008

10.練習

示例

class base

上面乙個有三個類base,derive,derive2,基類base中只定義了虛函式vfunc,base的子類derive中,定義了vfunc和vfunc2,但是vfunc和基類中的vfunc的形參列表不同,且子類中的vfunc沒有override關鍵字修飾,所以這兩個vfunc沒有任何關係,而derive的子類derive2中重寫了vfunc,且引數和base中的vfunc一致,所以,main中的前三個呼叫會中的前兩個會呼叫base中的vfunc,而第三個呼叫會呼叫derive2中的vfunc而vfunc2沒有在基類base中定義,又因為只能通過靜態型別解析能呼叫的成員,所以不能通過基類的指標呼叫vfunc2,所以中間三個的第乙個呼叫是錯誤的,而vfunc2是個虛函式,所以通過中間三個的後兩個呼叫會分別動態呼叫derive和derive2中的vfunc2同樣,因為基類中沒有定義帶引數的vfunc,所以不能通過基類的指標呼叫帶引數的vfunc,所以最後三個的第乙個呼叫是錯誤的,而帶引數的vfunc不是虛函式,所以是靜態呼叫,所以最後兩個會靜態呼叫derive和derive2中的帶引數的vfunc執行結果如下

上面兩個錯誤的呼叫也說明,如果基類中沒有定義對應的虛函式,只在子類中定義對應的虛函式,那麼即使通過基類的指標指向子類,也無法呼叫子類中的虛函式,無法使用虛機制,因為基類的靜態型別無法在基類中找到要呼叫的成員

11.基類的析構函式通常應該是virtual的

示例

class base3

{public:

base3(){cout<<__func__ alt="" height="106" src="" width="553">

上述**的輸出結果非常正常,但是如果要把base3中的析構函式的virtual關鍵字去掉,就會變得不正常

從輸出結果上看,不僅彈出了了乙個警告(銷毀含有非虛析構函式的多型類將導致不確定性為),而且還沒有呼叫子類的析構函式,有可能在子類物件析構的時候導致記憶體洩漏

原因:1.因為繼承的關係,靜態型別和動態型別很有可能不一致。此時,delete基類指標時需要正確呼叫對應版本的析構函式,如果動態型別是基類,那麼只呼叫基類的析構函式即可,此時基類的析構函式是不是虛的無所謂。

2.如果基類指標指向乙個動態分配的子類物件,此時,如果基類的析構函式非虛,那麼delete 基類指標時,不會觸發虛機制,就只會釋放子類物件中的基類的部分,導致子類物件銷毀不徹底,子類中的成員無法**,出現記憶體洩露。如果基類的析構函式是virtual的,那麼在delete基類指標銷毀子類物件時,會觸發虛機制,會先動態呼叫子類的析構函式,而子類部分銷毀後,根據派生類中析構函式的呼叫順序,會接著呼叫基類的析構函式。這樣,當基類指標指向乙個動態分配的子類物件時,就可以正確的釋放動態分配的子類物件。

12.在建構函式和析構函式中呼叫虛函式

因為乙個子類物件在建立時,先建立基類部分,然後再建立子類部分,如果在基類的建構函式中呼叫虛函式,此時子類的特有部分還沒有構建,因此雖然會動態呼叫虛函式,但是呼叫的是基類中的虛函式,達不到多型的效果

同理,乙個子類物件在銷毀時,先銷毀子類部分,呼叫子類的析構函式,然後再銷毀基類部分,呼叫基類的析構函式,如果在基類的析構函式中呼叫虛函式,此時子類的特有部分已經被銷毀,因此雖然會動態呼叫虛函式,但是呼叫的是基類中的虛函式,也達不到多型的效果

示例class base3

{public:

base3(){cout<<__func__ alt="" height="131" src="" width="553">

二、純虛函式與抽象類

1.純虛函式在虛函式宣告處的最後加個=0就可以將乙個虛函式變為純虛函式,純虛函式通常不用(但是可以)定義,如果定義的話,需要將純虛函式定義在類的外部。

2.含有純虛函式的類就是抽象類。因為含有純虛函式,所以不能直接定義純虛類的物件,只能定義純虛類的指標或者引用,然後指向乙個繼承該類的子類物件

示例class animal

{public:

animal():legs(2), wing(false){cout<<__func__ alt="" height="126" src="" width="553">

和虛函式一樣,純虛函式也能實現多型,但是子類通常應該(可以不)實現自定義版本的純虛函式,否則繼承純虛類後,如果有些純虛函式沒有重新實現,繼承到子類裡依然是純虛函式,子類依然是個純虛類

3.有了虛函式為啥還要純虛函式

虛函式能實現多型,純虛函式也能實現多型,那麼純虛函式的作用體現在**呢?

除了多型,還有個很重要的原因就是在很多情況下,基類本身生成物件是不合情理的。例如,形狀作為乙個基類可以派生出三角形,正方形,梯形等,但形狀本身生成物件明顯不合常理。所以純虛類一般用來描述定義比較抽象的概念,比如動物,形狀,燈,樹木等等並定義一堆純虛函式(介面),然後再由一些表示具體概念的類來繼承該抽象類進行具體實現。

參考《c++ primer》

C 知識點50 虛函式與純虛函式(上)

一 虛函式 1.如果乙個基類希望基類中的某些成員函式在子類中實現子類的自定義版本,就可以將該成員函式定義為virtual。2.當使用基類的指標或引用呼叫乙個虛函式時,將會發生動態繫結 在執行時根據指標或引用的動態型別來決定呼叫對應動態型別中的虛函式 動態繫結發生時,編譯器無法在編譯時確定要呼叫哪個版...

純虛函式 虛函式 普通成員函式的知識點

1 如果乙個類的成員至少有乙個是純虛函式,那麼這個類就是純虛類。2 試圖例項化乙個抽象類物件 即包括乙個或多個純虛函式的類 是一種語法錯誤。3 如果乙個類的成員全部都是純虛函式,那麼這個類就是純虛類。4 純虛函式是用來表示介面的。5 如果乙個類的成員全部都是純虛函式,那麼這個類就是抽象類,也即介面。...

C 虛函式與純虛函式

純虛函式定義如下 virtual functionname parameter 0 類的乙個成員定位虛函式的實際意義在於讓c 知道該函式並無意義,它的作用只是為了讓派生類進行函式過載保留位置。純虛函式的定義方法就是在類的虛函式後面加上 0 標記,類中一旦出現了純虛函式的定義,那麼此類為抽象類。例項 ...