天天看點

虛函數&多态

對于經常被問到的虛函數和多态的問題,發現百度百科回答得十分詳細,是以自己在百度百科上的解釋進行總結

一、虛函數

(1)虛函數簡介:在某基類中聲明為virtual并在一個或者多個派生類中被重新定義的成員函數;實作多态性,通過指向派生類的基類指針或引用,通路派生類中同名覆寫成員函數。

(2)簡單解釋:被virtual關鍵字修飾的成員函數,就是虛函數。

(3)作用:實作多态性(polymorphism)。

(4)過程說明:

  先給定代碼,對以下代碼做說明:

輸出結果:

虛函數&多态

對于上面代碼,通過class Animal和class Dog的speak( )函數接口,可以看出這兩個class因個體差異而采取不同的行為,但是卻沒有滿足多态性,因為多态性的關鍵是:一切用指向基類的指針或引用來操作對象。是以我們對main( )函數做修改,采用指向基類的指針或引用來調用:

 輸出結果:

虛函數&多态

由輸出可以看,兩個調用輸出的都是Animal自己的speak( )函數,這不符合我們的要求,是以引入了虛函數,來解決此問題;是以在基類的成員函數定義前加virtual:

虛函數&多态

 作為基類的Animal的成員函數speak( )被定義為虛函數,相應的其派生類Dog的成員函數speak( )自動變為虛函數;是以對于派生類中相應成員函數是否加上virtual關鍵字修飾,是可選的,但是為了可讀性,一般還是加上。

(5)限制條件:

非類的成員函數不能定義為虛函數,類的成員函數中靜态函數、構造函數也不能定義為虛函數,但是析構函數可以被定義為虛函數;

當基類中的某一成員函數聲明為虛函數後,派生類中的同名函數(函數名相同、參數清單完全一緻、傳回類型相關)自動成為虛函數;

如果聲明了某個成員函數為虛函數,則在該類中不能出現和這個成員函數同名并且傳回值、參數個數、類型都相同的非虛函數;在以該類為基類的派生類中,也不能出現這種同名函數。

(6)總結:

指向基類的指針在操作它的多态對象時,會根據不同的類對象,調用其相應的函數,這個函數就是虛函數;

虛函數聯系到多态,多态聯系到繼承。

二、多态性

  多态是指同一個實體同時具有多種形式。它是面向對象程式設計的一個重要特征。如果一個語言支援類而不支援多态,隻能說明它是基于對象的,而不是面向對象的。

  C++中的多态性具體展現在運作和編譯兩個方面。

運作時,為動态多态,具體引用的對象要在運作時才能确定;

編譯時,為靜态多态,在編譯時就可以确認對象使用的形式。

(1)定義:多态是指同一操作作用于不同的對象,可以有不同的解釋,産生不同的執行結果。在運作時,可以通過指向基類的指針,來調用實作派生類中的方法。

(2)實作方法:C++中,實作多态可以通過虛函數、抽象類、覆寫、模闆(重構與多态無關)。

(3)作用:

  把不同的子類對象都當作父類來看,可以屏蔽不同子類對象之間的差異,寫出通用的代碼,做出通用的程式設計,以适應需求的不斷變化。

  指派之後,父類型的引用就可以根據目前指派給它的子對象的特性以不同的方式運作。也就是說,父親的行為像兒子,而不是兒子的行為像父親。

  舉個例子:從一個基類中派生,響應一個虛指令,産生不同的結果。

  比如從某個基類派生出多個子類,其基類有一個虛方法Tdoit,然後其子類也有這個方法,但行為不同,然後這些子類對象中的任何一個可以賦給其基類對象的引用,或者說将子對象位址賦給基類指針,這樣其基類的對象就可以執行不同的操作了。實際上你是在通過其基類的引用來通路其子類對象的,你要做的就是一個指派操作。

  使用繼承性的結果就是當建立了一個類的家族,在認識這個類的家族時,就是把子類的對象當作基類的對象,這種認識又叫作upcasting(向上轉型)。這樣認識的重要性在于:我們可以隻針對基類寫出一段程式,但它可以适應于這個類的家族,因為編譯器會自動找出合适的對象來執行操作。這種現象又稱為多态性。而實作多态性的手段又叫稱動态綁定(dynamic binding)。

  簡單的說,建立一個父類對象的引用,它所指對象可以是這個父類的對象,也可以是它的子類的對象。java中當子類擁有和父類同樣的函數,當通過這個父類對象的引用調用這個函數的時候,調用到的是子類中的函數。

三、重構

  一種糟糕的現象:軟體産品最初制造出來,是經過精心的設計,具有良好架構的。但是随着時間的發展、需求的變化,必須不斷的修改原有的功能、追加新的功能,還免不了有一些缺陷需要修改。為了實作變更,不可避免的要違反最初的設計構架。經過一段時間以後,軟體的架構就千瘡百孔了。bug越來越多,越來越難維護,新的需求越來越難實作,軟體的架構對新的需求漸漸的失去支援能力,而是成為一種制約。最後新需求的開發成本會超過開發一個新的軟體的成本,這就是這個軟體系統的生命走到盡頭的時候。

  重構就能夠最大限度的避免這樣一種現象。系統發展到一定階段後,使用重構的方式,不改變系統的外部功能,隻對内部的結構進行重新的整理。通過重構,不斷的調整系統的結構,使系統對于需求的變更始終具有較強的适應能力。

  重構可以降低項目的耦合度,使項目更加子產品化,有利于項目的開發效率和後期的維護。讓項目主架構突出鮮明,給人一種思路清晰,一目了然的感覺,其實重構是對架構的一種維護。