在幫新同事進行**審查的時候,常常會發現這樣的問題:**中原有基類b和派生類d1,現在新加乙個派生類d2,它有乙個函式f2()。由於經驗不足,新同事並沒有注意到d1也有類似的函式f1()。於是造成了類似的**出現在了兩個地方,**冗餘造成將來的維護工作異常困難。注意到f()實際上是乙個通用的行為,我們可以把它抽出來放到基類中,如下所示。
[cpp]view plain
copy
print?
class b
; void b::f()
class d1: public b ;
class d2: public b ;
class b
;void b::f()
class d1: public b ;
class d2: public b ;
這裡有兩點。基類裡面的f()有函式定義是為了避免**冗餘,因為d1和d2關於f的實現都是相同的。f()是虛函式是考慮到將來萬一有乙個派生類需要f()有不同的實現方式時,它可以重新定義f。
到目前為止一切順利。好了,假設現在另乙個同事又加了乙個派生類d3,它要求f()有不同的實現方式。但是,他忘記了重新定義f。。這是乙個災難。
[cpp]view plain
copy
print?
class d3: public b ;
b* b = new d3;
// f做的動作不是我希望的!
b->f();
class d3: public b ;
b* b = new d3;
// f做的動作不是我希望的!
b->f();
注意,這個問題的本質並不是說基類不能有預設的實現,而是說如果派生類需要使用基類預設的實現,必須顯式地表示出來。所以,我們需要乙個能夠強制派生類定義f的方式,答案就是純虛函式。
[cpp]view plain
copy
print?
class b
; class d3: public b ;
b* b = new d3; // 編譯報錯:抽象類無法例項化
b->f();
class b
;class d3: public b ;
b* b = new d3; // 編譯報錯:抽象類無法例項化
b->f();
我們知道有純虛函式的類是抽象類,而抽象類是無法例項化的。如果d3沒有實現f,那麼d3也無法例項化。這就要求每個要例項化的子類都必須顯示地實現純虛函式f。另一方面,f的預設實現放**?
一種方法是把預設實現作為另乙個非虛函式放在基類裡,當然它是保護的,這樣外界無妨直接訪問而派生類可以通過呼叫該函式來達到預設的行為。
[cpp]view plain
copy
print?
class b
; void b::f_impl()
// d2類似
class d1: public b
; void d1::f()
class d3: public b
; void d3::f()
class b
;void b::f_impl()
// d2類似
class d1: public b
;void d1::f()
class d3: public b
;void d3::f()
第二種方法是把預設的實現放入基類純虛函式的函式體。沒錯,純虛函式可以有函式定義存在,它的作用就是提供虛函式預設的實現方式。和一般虛函式不同,派生類必須重新定義純虛函式。如果需要使用預設實現,也必須顯式地呼叫基類的相關函式。
[cpp]view plain
copy
print?
class b
; void b::f()
// d2類似
class d1: public b
; void d1::f()
class b
;void b::f()
// d2類似
class d1: public b
;void d1::f()
這種方法的好處是少了乙個需要維護的函式,缺點是客戶**可以直接呼叫基類的預設實現。
[cpp]view plain
copy
print?
b* b = new d1;
b->b::f();
b* b = new d1;
b->b::f();
小結:
普通的虛函式提供了介面與預設實現。(公有繼承的)派生類繼承介面的同時可以自動繼承介面的預設實現(免費的午餐),或者選擇重新定義該函式來特化自己的行為。風險是以後需要定製此行為的派生類可能因為忘記重定義而錯誤地使用預設實現。
純虛函式只提供了介面。但是具有函式體的純虛函式同時還提供了預設實現。派生類必須顯式定義介面。可以通過顯式呼叫基類函式來完成預設行為。
為了完整,順便補充一下,公有非虛函式提供了介面與強制實現。也就是說所有的派生類必須繼承這個介面及其實現。
虛函式 純虛函式
一 定義.純虛函式是在基類中宣告的虛函式,它在基類中沒有定義,但要求任何派生類都要定義自己的實現方法。在基類中實現純虛函式的方法是在函式原型後加 0 virtual void funtion1 0 二 引入原因 1 為了方便使用多型特性,我們常常需要在基類中定義虛函式。2 在很多情況下,基類本身生成...
虛函式 純虛函式
虛函式的作用是允許在派生類中重新定義與基類同名的函式,並且可以通過基類指標引用來訪問基類和派生類中的同名函式。include using namespace std class student student類成員函式的實現 宣告抽象基類shape class shape virtual float...
虛函式和純虛函式
除了繼承外,c 的另乙個優良特性是支援多型,即允許將派生類的物件當作基類的物件使用。如果a是基類,b和c是a的派生類,多態函式test的引數是a的指標。那麼test函式可以引用a b c的物件。示例程式如下 class a void test a a class b public a class c...