C++的多型

thesby發表於2016-06-15

C++的多型一直是初級程式設計師的痛,因為總感覺找不到裡面的套路。一般講到的多型往往和虛擬函式有關,但有的書籍講到模板和過載也算多型,只不過是靜態多型,即在編譯器就確定了函式的呼叫形式。我們這裡遵從大多數認為的,也就是前者的動態多型,只有在執行期間才能確定函式的呼叫。

什麼是多型

物件導向程式設計有三個重要的特點:封裝、繼承、多型。
這裡寫圖片描述
下面借用http://blog.csdn.net/ruyue_ruyue/article/details/8211809部落格的話解釋下這些是什麼意思。


封裝

什麼是封裝?
封裝可以隱藏實現細節,使得程式碼模組化;封裝是把過程和資料包圍起來,對資料的訪問只能通過已定義的介面。物件導向計算始於這個基本概念,即現實世界可以被描繪成一系列完全自治、封裝的物件,這些物件通過一個受保護的介面訪問其他物件。在物件導向程式設計上可理解為:把客觀事物封裝成抽象的類,並且類可以把自己的資料和方法只讓可信的類或者物件操作,對不可信的進行資訊隱藏。

繼承

什麼是繼承?
繼承是指這樣一種能力:它可以使用現有類的所有功能,並在無需重新編寫原來的類的情況下對這些功能進行擴充套件。其繼承的過程,就是從一般到特殊的過程。
通過繼承建立的新類稱為“子類”或“派生類”。被繼承的類稱為“基類”、“父類”或“超類”。要實現繼承,可以通過“繼承”(Inheritance)和“組合”(Composition)來實現。在某些 OOP 語言中,一個子類可以繼承多個基類。但是一般情況下,一個子類只能有一個基類,要實現多重繼承,可以通過多級繼承來實現。
繼承的實現方式?
繼承概念的實現方式有三類:實現繼承、介面繼承和可視繼承。
1. 實現繼承是指使用基類的屬性和方法而無需額外編碼的能力;
2. 介面繼承是指僅使用屬性和方法的名稱、但是子類必須提供實現的能力;
3. 可視繼承是指子窗體(類)使用基窗體(類)的外觀和實現程式碼的能力。

多型

什麼是多型?
多型性(polymorphisn)是允許你將父物件設定成為和一個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作。簡單的說,就是一句話:允許將子類型別的指標賦值給父類型別的指標。


什麼是過載、覆蓋(重寫)、隱藏?

過載

過載是一種通過定義同名但是接受不同引數列表的函式,來實現一個統一的呼叫介面。比如要實現一個加法,需要接受int、float、double、甚至自定義的資料型別,我們的函式只取一個名字add(),但是可以實現多種不同的輸入。在外部看來,這裡相當於只有一個介面在被呼叫,不需要只要其實在內部是由不同函式來實現的。必須說明的是,過載是不考慮返回值的。

過載只能發生在一個作用域內部,比如在一在一個類當中。所以,兩個類裡面是不會發生過載的,就算是繼承的關係。

覆蓋(重寫)

覆蓋是指派生類函式覆蓋基類函式,特徵是:

  • 不同的範圍(分別位於派生類與基類);
  • 函式名字相同;
  • 引數相同;
  • 基類函式必須有virtual 關鍵字。

類如果有虛擬函式,都會存在虛擬函式表,有關虛擬函式表,可以參考這裡,
http://www.cnblogs.com/Ripper-Y/archive/2012/05/15/2501930.html
http://my.oschina.net/hnuweiwei/blog/280894
子類在繼承父類時,如果父類有虛擬函式,那麼父類的虛擬函式表會被複制到子類的虛擬函式表中。所以當基類的函式有virtual時,如果子類也定義了一個同名且引數列表相同(也就是函式簽名相同)時,那麼基類的虛擬函式表複製到子類後,這個位置由於與子類簽名相同,會被覆蓋掉,所以就發生了覆蓋。

隱藏

  • (1)如果派生類的函式與基類的函式同名,但是引數不同。此時,不論有無virtual關鍵字,基類的函式將被隱藏(注意別與過載混淆)。
  • (2)如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有virtual關鍵字。此時,基類的函式被隱藏(注意別與覆蓋混淆)。

對於第一條,子類與基類函式簽名不同,子類肯定不會去呼叫基類函式,而且隱藏了父類的該函式。對於第二條,簽名相同,基類函式沒有使用virtual,則它不在虛擬函式表中,不可能被覆蓋,只是被隱藏了。

為什麼需要多型

感覺一個c++有必要整得這麼複雜嗎?額,我個人感覺相比java,C++過於學究了。為了實現類繼承之間的多型性,必須搞得足夠複雜才能carry一切。
覆蓋的作用很明顯,就是子類將基類的虛擬函式覆蓋掉。比如基類定義了很多虛擬函式介面,然後不同的子類就實現這些介面,這樣可以讓子類自己定義自己的功能,但是有著統一的介面,很方便管理。
既然有了覆蓋,為什麼還需要隱藏呢?難道覆蓋還不夠嗎?對,覆蓋是將基類的虛擬函式覆蓋掉了,但是有時候不是想覆蓋呢?比如,

PS

巨集多型

相關文章