詳解C++多態(tài)的實(shí)現(xiàn)及原理

C++的多態(tài)性用一句話概括就是:在基類的函數(shù)前加上virtual關(guān)鍵字,在派生類中重寫該函數(shù),運(yùn)行時(shí)將會(huì)根據(jù)對(duì)象的實(shí)際類型來(lái)調(diào)用相應(yīng)的函數(shù)。如果對(duì)象類型是派生類,就調(diào)用派生類的函數(shù);如果對(duì)象類型是基類,就調(diào)用基類的函數(shù)

成都創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都做網(wǎng)站、成都網(wǎng)站制作、安澤網(wǎng)絡(luò)推廣、小程序制作、安澤網(wǎng)絡(luò)營(yíng)銷、安澤企業(yè)策劃、安澤品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);成都創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供安澤建站搭建服務(wù),24小時(shí)服務(wù)熱線:13518219792,官方網(wǎng)址:muchs.cn

  1:用virtual關(guān)鍵字申明的函數(shù)叫做虛函數(shù),虛函數(shù)肯定是類的成員函數(shù)。 

  2:存在虛函數(shù)的類都有一個(gè)一維的虛函數(shù)表叫做虛表,類的對(duì)象有一個(gè)指向虛表開始的虛指針。虛表是和類對(duì)應(yīng)的,虛表指針是和對(duì)象對(duì)應(yīng)的。 

  3:多態(tài)性是一個(gè)接口多種實(shí)現(xiàn),是面向?qū)ο蟮暮诵?,分為類的多態(tài)性和函數(shù)的多態(tài)性。 

  4:多態(tài)用虛函數(shù)來(lái)實(shí)現(xiàn),結(jié)合動(dòng)態(tài)綁定. 

  5:純虛函數(shù)是虛函數(shù)再加上 = 0; 

  6:抽象類是指包括至少一個(gè)純虛函數(shù)的類。

純虛函數(shù):virtual void fun()=0;即抽象類!必須在子類實(shí)現(xiàn)這個(gè)函數(shù),即先有名稱,沒(méi)有內(nèi)容,在派生類實(shí)現(xiàn)內(nèi)容。

下面看下c++語(yǔ)言虛函數(shù)實(shí)現(xiàn)多態(tài)的原理

自上一個(gè)帖子之間跳過(guò)了一篇總結(jié)性的帖子,之后再發(fā),今天主要研究了c++語(yǔ)言當(dāng)中虛函數(shù)對(duì)多態(tài)的實(shí)現(xiàn),感嘆于c++設(shè)計(jì)者的精妙絕倫

c++中虛函數(shù)表的作用主要是實(shí)現(xiàn)了多態(tài)的機(jī)制。首先先解釋一下多態(tài)的概念,多態(tài)是c++的特點(diǎn)之一,關(guān)于多態(tài),簡(jiǎn)而言之就是 用父類的指針指向其子類的實(shí)例,然后通過(guò)父類的指針調(diào)用實(shí)際子類的成員函數(shù),這種方法呢,可以讓父類的指針具有多種形態(tài),也就是說(shuō)不需要改動(dòng)很多的代碼就可以讓父類這一種指針,干一些很多子類指針的事情,這里是從虛函數(shù)的實(shí)現(xiàn)機(jī)制層面進(jìn)行研究

在寫這篇帖子之前對(duì)于相關(guān)的文章進(jìn)行了查閱,基本上是大段的文字,所以我的這一篇可能會(huì)用大量的圖形進(jìn)行贅述(如果理解有誤的地方,煩請(qǐng)大佬能夠指出),接下來(lái)就言歸正傳:

首先介紹一下為什么會(huì)引進(jìn)多態(tài)呢,基于c++的復(fù)用性和拓展性而言,同類的程序模塊進(jìn)行大量重復(fù),是一件無(wú)法容忍的事情,比如我設(shè)置了蘋果,香蕉,西瓜類,現(xiàn)在想把這些東西都裝到碗這個(gè)函數(shù)里,那么在主函數(shù)當(dāng)中,聲明對(duì)象是必須的,但是每一次裝進(jìn)碗里對(duì)于水果來(lái)說(shuō),都要用自己的指針調(diào)用一次裝的功能,那為什么不把這些類抽象成一個(gè)水果類呢,直接定義一個(gè)水果類的指針一次性調(diào)用所有水果裝的功能呢,這個(gè)就是利用父類指針去調(diào)用子類成員,但是這個(gè)思想受到了指針指向類型的限制,也就是說(shuō)表面指針指向了子類成員,但實(shí)際上還是只能調(diào)用子類成員里的父類成員,這樣的思想就變的毫無(wú)意義了,如果想要解決這個(gè)問(wèn)題,只要在父類前加上virtual就可以解決了,這里就是利用虛函數(shù)實(shí)現(xiàn)多態(tài)的實(shí)例。

首先還是作為舉例來(lái)兩個(gè)類,在之前基礎(chǔ)知識(shí)的帖子中提到過(guò),空類的大小是一個(gè)字節(jié)(占位符),函數(shù),靜態(tài)變量都在編譯期就形成了,不用類去分配空間,但是做一個(gè)小實(shí)驗(yàn),看一看在定義了虛函數(shù)之后,類的大小是多少呢

#include<iostream>
using namespace std;
class CFather 
{
public:
 virtual void AA()  //虛函數(shù)標(biāo)識(shí)符
 {
 cout << "CFather :: AA()" << endl;
 }
 void BB()
 {
 cout << "CFather :: BB()" << endl;
 }
};
class CSon : public CFather
{
public:
 void AA()
 {
 cout << "CSon :: AA()" << endl;
 }
 void BB()
 {
 cout << "CSon :: BB()" << endl;
 }
};
int main()
{
 cout << sizeof(CFather) << endl;       //測(cè)試加了虛函數(shù)的類
 system("pause");
 return 0;
}

詳解C++ 多態(tài)的實(shí)現(xiàn)及原理

很明顯類里裝了一個(gè) 4個(gè)字節(jié)的東西,除了整形int,就是指針了,沒(méi)錯(cuò)這里裝的就是函數(shù)指針

先把這個(gè)代碼,給抽象成圖形進(jìn)行理解,在這CFather為A,CSon為B

詳解C++ 多態(tài)的實(shí)現(xiàn)及原理

此時(shí)就是一個(gè)單純的繼承的情況,不存在虛函數(shù),然后我new一個(gè)對(duì)象,A *p = new A;那么 p -> AA(),必然是指向A類中的AA()函數(shù),那么函數(shù)的調(diào)用有兩種方式 一種函數(shù)名加()直接調(diào)用,一種是利用函數(shù)指針進(jìn)行調(diào)用,在這里我想要調(diào)用子類的,就可以利用函數(shù)指針進(jìn)行調(diào)用,假設(shè)出來(lái)兩個(gè)函數(shù)指針,來(lái)指向B類中的兩個(gè)成員函數(shù),如果我父類想要調(diào)用子類成員,就可以通過(guò) p指針去調(diào)用函數(shù)指針,再通過(guò)函數(shù)指針去調(diào)用成員函數(shù)

詳解C++ 多態(tài)的實(shí)現(xiàn)及原理

每一個(gè)函數(shù)都可以用一個(gè)函數(shù)指針去指著,那么每一類中的函數(shù)指針都可以形成自己的一個(gè)表,這個(gè)就叫做虛函數(shù)表

詳解C++ 多態(tài)的實(shí)現(xiàn)及原理

那么在創(chuàng)建對(duì)象后,為什么類中會(huì)有四個(gè)字節(jié)的內(nèi)存空間呢?

在C++的標(biāo)準(zhǔn)規(guī)格說(shuō)明書中說(shuō)到,編譯器必需要保證虛函數(shù)表的指針存在于對(duì)象中最前面的位置(這是為了保證正確取到虛函數(shù)的偏移量)。這意味著我們通過(guò)對(duì)象實(shí)例的地址得到這張?zhí)摵瘮?shù)表,然后就可以遍歷其中函數(shù)指針,并調(diào)用相應(yīng)的函數(shù)。也就是說(shuō)這四個(gè)字節(jié)的指針,代替了上圖中(p->*pfn)()的作用,指向了函數(shù)指針,也就是說(shuō),在使用了虛函數(shù)的父類成員函數(shù),雖然寫的還是p->AA(),實(shí)際上卻是,(p->*(vfptr[0])),而指向哪個(gè)虛函數(shù)表就由,創(chuàng)建的對(duì)象來(lái)決定

詳解C++ 多態(tài)的實(shí)現(xiàn)及原理

至此,就能理解如何用虛函數(shù)這個(gè)機(jī)制來(lái)實(shí)現(xiàn)多態(tài)的了

下面,我將分別說(shuō)明“無(wú)覆蓋”和“有覆蓋”時(shí)的虛函數(shù)表的樣子。沒(méi)有覆蓋父類的虛函數(shù)是毫無(wú)意義的。我之所以要講述沒(méi)有覆蓋的情況,主要目的是為了給一個(gè)對(duì)比。在比較之下,我們可以更加清楚地知道其內(nèi)部的具體實(shí)現(xiàn)。

無(wú)虛數(shù)覆蓋

下面,再讓我們來(lái)看看繼承時(shí)的虛函數(shù)表是什么樣的。假設(shè)有如下所示的一個(gè)繼承關(guān)系:

詳解C++ 多態(tài)的實(shí)現(xiàn)及原理

請(qǐng)注意,在這個(gè)繼承關(guān)系中,子類沒(méi)有重載任何父類的函數(shù)。那么,在派生類的實(shí)例中,Derive d; 的虛函表:

詳解C++ 多態(tài)的實(shí)現(xiàn)及原理

我們可以看到下面幾點(diǎn):

1)虛函數(shù)按照其聲明順序放于表中。

2)父類的虛函數(shù)在子類的虛函數(shù)前面。

有虛數(shù)覆蓋

覆蓋父類的虛函數(shù)是很顯然的事情,不然,虛函數(shù)就變得毫無(wú)意義。下面,我們來(lái)看一下,如果子類中有虛函數(shù)重載了父類的虛函數(shù),會(huì)是一個(gè)什么樣子?假設(shè),我們有下面這樣的一個(gè)繼承關(guān)系。

詳解C++ 多態(tài)的實(shí)現(xiàn)及原理

為了讓大家看到被繼承過(guò)后的效果,在這個(gè)類的設(shè)計(jì)中,我只覆蓋了父類的一個(gè)函數(shù):f()。那么,對(duì)于派生類的實(shí)例,其虛函數(shù)表會(huì)是下面的一個(gè)樣子:

詳解C++ 多態(tài)的實(shí)現(xiàn)及原理

我們從表中可以看到下面幾點(diǎn),

1)覆蓋的f()函數(shù)被放到了虛表中原來(lái)父類虛函數(shù)的位置。

2)沒(méi)有被覆蓋的函數(shù)依舊。

這樣,我們就可以看到對(duì)于下面這樣的程序,

Base *b = new Derive();

b->f();

由b所指的內(nèi)存中的虛函數(shù)表的f()的位置已經(jīng)被Derive::f()函數(shù)地址所取代,于是在實(shí)際調(diào)用發(fā)生時(shí),是Derive::f()被調(diào)用了。這就實(shí)現(xiàn)了多態(tài)。

總結(jié)

以上所述是小編給大家介紹的c++語(yǔ)言虛函數(shù)實(shí)現(xiàn)多態(tài)的原理,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)創(chuàng)新互聯(lián)網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!

新聞標(biāo)題:詳解C++多態(tài)的實(shí)現(xiàn)及原理
文章分享:http://muchs.cn/article0/pipeoo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、網(wǎng)站建設(shè)電子商務(wù)、用戶體驗(yàn)、企業(yè)網(wǎng)站制作外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁(yè)設(shè)計(jì)公司