一、多態(tài)的概念
在說(shuō)多態(tài)之前,我們來(lái)先看一看對(duì)象的類(lèi)型

來(lái)看一個(gè)例子:

多態(tài):意思既是同一個(gè)事物的多種形態(tài),用我們C++的專(zhuān)業(yè)詞語(yǔ)來(lái)說(shuō)就是:一個(gè)借口、多種實(shí)現(xiàn)方式。
二、多態(tài)分類(lèi)

靜態(tài)多態(tài):
靜態(tài)多態(tài):編譯器在編譯期間完成的,編譯器根據(jù)函數(shù)實(shí)參的類(lèi)型(可能會(huì)進(jìn)行隱式類(lèi)型轉(zhuǎn)換),可推斷出要調(diào)用那個(gè)函數(shù),如果有對(duì)應(yīng)的函數(shù)就調(diào)用該函數(shù),否則出現(xiàn)編譯錯(cuò)誤。
動(dòng)態(tài)多態(tài):
動(dòng)態(tài)多態(tài)就是我們常說(shuō)的多態(tài)。動(dòng)態(tài)多態(tài)是在程序運(yùn)行期間才決定調(diào)用哪個(gè)函數(shù),是根據(jù)虛函數(shù)表實(shí)現(xiàn)的。聲明了虛函數(shù)的類(lèi),類(lèi)中都有一張?zhí)摵瘮?shù)表,里面存放類(lèi)的入口地址。通過(guò)賦值兼容規(guī)則,可以用父類(lèi)的指針或引用找到子類(lèi)的虛函數(shù)。虛函數(shù)是處理類(lèi)的派生體系中不同層次上不同作用域的同名問(wèn)題,因此動(dòng)態(tài)多態(tài)必須在類(lèi)的繼承體系中才能實(shí)現(xiàn)。
三、多態(tài)的實(shí)現(xiàn)原理(動(dòng)態(tài))
說(shuō)到這里,有幾個(gè)非常重要的概念,需要我們加以區(qū)分:重載、重寫(xiě)、重定義
通過(guò)上面的多態(tài)的介紹,這里來(lái)說(shuō)幾個(gè)重要的概念:
(1)虛函數(shù)表指針:類(lèi)中除了定義成員函數(shù)之外還有一個(gè)成員是虛函數(shù)表指針(占四個(gè)基本內(nèi)存單位),這個(gè)指針指向一個(gè)虛函數(shù)表的起始位置,這個(gè)表會(huì)與類(lèi)的定義同時(shí)出現(xiàn),這個(gè)表會(huì)與類(lèi)的定義同時(shí)出現(xiàn),這個(gè)表存放著該類(lèi)的虛函數(shù)指針,調(diào)用的時(shí)候可以找到該類(lèi)虛函數(shù)表指針,通過(guò)虛函數(shù)表指針找到虛函數(shù)表,通過(guò)虛函數(shù)表的偏移找到函數(shù)的入口地址,從而找到要使用的虛函數(shù)。
(2)當(dāng)實(shí)例化一個(gè)該類(lèi)的子類(lèi)對(duì)象的時(shí)候,(如果)該類(lèi)的子類(lèi)并沒(méi)有定義虛函數(shù),但是卻從父類(lèi)中繼承了虛函數(shù),所以在實(shí)例化該類(lèi)子類(lèi)對(duì)象的時(shí)候也會(huì)產(chǎn)生一個(gè)虛函數(shù)表,這個(gè)虛函數(shù)表是子類(lèi)的虛函數(shù)表,但是記錄的子類(lèi)的虛函數(shù)地址卻是與父類(lèi)的是一樣的。所以通過(guò)子類(lèi)對(duì)象的虛函數(shù)表指針找到自己的虛函數(shù)表,在自己的虛函數(shù)表找到的要執(zhí)行的函數(shù)指針也是父類(lèi)的相應(yīng)函數(shù)入口的地址。
(3)如果我們?cè)谧宇?lèi)中定義了從父類(lèi)繼承來(lái)的虛函數(shù),對(duì)于父類(lèi)來(lái)說(shuō)情況是不變的,對(duì)于子類(lèi)來(lái)說(shuō)它的虛函數(shù)表與之前的虛函數(shù)表是一樣的,但是此時(shí)子類(lèi)定義了自己的(從父類(lèi)那繼承來(lái)的)相應(yīng)函數(shù),所以它的虛函數(shù)表當(dāng)中管于這個(gè)函數(shù)的指針就會(huì)覆蓋掉原有的指向父類(lèi)函數(shù)的指針的值,換句話說(shuō)就是指向了自己定義的相應(yīng)函數(shù),這樣如果用父類(lèi)的指針,指向子類(lèi)的對(duì)象,就會(huì)通過(guò)子類(lèi)對(duì)象當(dāng)中的虛函數(shù)表指針找到子類(lèi)的虛函數(shù)表,從而通過(guò)子類(lèi)的虛函數(shù)表找到子類(lèi)的相應(yīng)虛函數(shù)地址,而此時(shí)的地址已經(jīng)是該函數(shù)自己定義的虛函數(shù)入口地址,而不是父類(lèi)的相應(yīng)虛函數(shù)入口地址,所以執(zhí)行的將會(huì)是子類(lèi)當(dāng)中的虛函數(shù)。這就是多態(tài)的原理。
(4)純虛函數(shù)
在成員函數(shù)的參數(shù)列表后面寫(xiě)上“=0”則該成員函數(shù)為純虛函數(shù)。
包含純虛函數(shù)的類(lèi)叫做抽象類(lèi)(也叫接口類(lèi)),抽象類(lèi)不能實(shí)例化出對(duì)象。
純虛函數(shù)在抽象類(lèi)中重新定義以后,派生類(lèi)才能實(shí)現(xiàn)實(shí)例化出對(duì)象。

總結(jié):
(1)派生類(lèi)重寫(xiě)基類(lèi)的虛函數(shù)實(shí)現(xiàn)多態(tài),要求函數(shù)名、參數(shù)列表、返回值完全相同(協(xié)變除外)
協(xié)變:基類(lèi)和派生類(lèi)中的虛函數(shù)名字和參數(shù)列表相同、返回值類(lèi)型不同,基類(lèi)中的虛函數(shù)返回Base*,派生類(lèi)中的虛函數(shù)返回Derived*
(2)基類(lèi)中定義了虛函數(shù),在派生類(lèi)中該函數(shù)始終保持虛函數(shù)的特性。
(3)只有類(lèi)的非靜態(tài)成員函數(shù)才能定義為虛函數(shù),靜態(tài)成員函數(shù)不能定義為虛函數(shù)。
(4)如果在類(lèi)外定義虛函數(shù),只能在聲明函數(shù)時(shí)加virtual關(guān)鍵字,定義時(shí)不用加。
(5)構(gòu)造函數(shù)不能定義為虛函數(shù),雖然可以將operator=定義為虛函數(shù),但最好不要這么做,使用時(shí)容易混淆
(6)不要在構(gòu)造函數(shù)和析構(gòu)函數(shù)中調(diào)用虛函數(shù),在構(gòu)造函數(shù)和析構(gòu)函數(shù)中,對(duì)象是不完整的,可能會(huì)出現(xiàn)未定義的行為。
(7)最好將基類(lèi)的析構(gòu)函數(shù)聲明為虛函數(shù)。(析構(gòu)函數(shù)比較特殊,因?yàn)榕缮?lèi)的析構(gòu)函數(shù)跟基類(lèi)的析構(gòu)函數(shù)名稱(chēng)不一樣,但是構(gòu)成覆蓋,這里編譯器做了特殊處理)
(8)虛表是對(duì)所有類(lèi)對(duì)象實(shí)例共用的
-
C++
+關(guān)注
關(guān)注
22文章
2124瀏覽量
77309 -
動(dòng)態(tài)多態(tài)
+關(guān)注
關(guān)注
0文章
4瀏覽量
6057 -
靜態(tài)多態(tài)
+關(guān)注
關(guān)注
0文章
2瀏覽量
5552
發(fā)布評(píng)論請(qǐng)先 登錄
C++的多態(tài)詳解
STM32 C++代碼封裝初探相關(guān)資料推薦
C++的動(dòng)態(tài)多態(tài)和靜態(tài)多態(tài)
java多態(tài)性的實(shí)現(xiàn)
C++程序設(shè)計(jì)教程之多態(tài)的詳細(xì)資料說(shuō)明
C++程序設(shè)計(jì)教程之多態(tài)性與虛函數(shù)的詳細(xì)資料說(shuō)明
C++三大特性:封裝的概念原理
C++基礎(chǔ)語(yǔ)法中的引用、封裝和多態(tài)
在C++中如何用虛函數(shù)實(shí)現(xiàn)多態(tài)
STM32 C++編程系列二:STM32 C++代碼封裝初探
如何通過(guò)poly實(shí)現(xiàn)C++編譯期多態(tài)
虛函數(shù),C++開(kāi)發(fā)者如何有效利用
深度解析C++中的虛函數(shù)
C++中實(shí)現(xiàn)類(lèi)似instanceof的方法
詳談C++特性:多態(tài)的概念分類(lèi)和實(shí)現(xiàn)原理
評(píng)論