亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

詳解C++ 多態的實現及原理

發布時間:2020-09-04 17:36:47 來源:腳本之家 閱讀:124 作者:mrr 欄目:編程語言

C++的多態性用一句話概括就是:在基類的函數前加上virtual關鍵字,在派生類中重寫該函數,運行時將會根據對象的實際類型來調用相應的函數。如果對象類型是派生類,就調用派生類的函數;如果對象類型是基類,就調用基類的函數

  1:用virtual關鍵字申明的函數叫做虛函數,虛函數肯定是類的成員函數。 

  2:存在虛函數的類都有一個一維的虛函數表叫做虛表,類的對象有一個指向虛表開始的虛指針。虛表是和類對應的,虛表指針是和對象對應的。 

  3:多態性是一個接口多種實現,是面向對象的核心,分為類的多態性和函數的多態性。 

  4:多態用虛函數來實現,結合動態綁定. 

  5:純虛函數是虛函數再加上 = 0; 

  6:抽象類是指包括至少一個純虛函數的類。

純虛函數:virtual void fun()=0;即抽象類!必須在子類實現這個函數,即先有名稱,沒有內容,在派生類實現內容。

下面看下c++語言虛函數實現多態的原理

自上一個帖子之間跳過了一篇總結性的帖子,之后再發,今天主要研究了c++語言當中虛函數對多態的實現,感嘆于c++設計者的精妙絕倫

c++中虛函數表的作用主要是實現了多態的機制。首先先解釋一下多態的概念,多態是c++的特點之一,關于多態,簡而言之就是 用父類的指針指向其子類的實例,然后通過父類的指針調用實際子類的成員函數,這種方法呢,可以讓父類的指針具有多種形態,也就是說不需要改動很多的代碼就可以讓父類這一種指針,干一些很多子類指針的事情,這里是從虛函數的實現機制層面進行研究

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

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

首先還是作為舉例來兩個類,在之前基礎知識的帖子中提到過,空類的大小是一個字節(占位符),函數,靜態變量都在編譯期就形成了,不用類去分配空間,但是做一個小實驗,看一看在定義了虛函數之后,類的大小是多少呢

#include<iostream>
using namespace std;
class CFather 
{
public:
 virtual void AA()  //虛函數標識符
 {
 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;       //測試加了虛函數的類
 system("pause");
 return 0;
}

詳解C++ 多態的實現及原理

很明顯類里裝了一個 4個字節的東西,除了整形int,就是指針了,沒錯這里裝的就是函數指針

先把這個代碼,給抽象成圖形進行理解,在這CFather為A,CSon為B

詳解C++ 多態的實現及原理

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

詳解C++ 多態的實現及原理

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

詳解C++ 多態的實現及原理

那么在創建對象后,為什么類中會有四個字節的內存空間呢?

在C++的標準規格說明書中說到,編譯器必需要保證虛函數表的指針存在于對象中最前面的位置(這是為了保證正確取到虛函數的偏移量)。這意味著我們通過對象實例的地址得到這張虛函數表,然后就可以遍歷其中函數指針,并調用相應的函數。也就是說這四個字節的指針,代替了上圖中(p->*pfn)()的作用,指向了函數指針,也就是說,在使用了虛函數的父類成員函數,雖然寫的還是p->AA(),實際上卻是,(p->*(vfptr[0])),而指向哪個虛函數表就由,創建的對象來決定

詳解C++ 多態的實現及原理

至此,就能理解如何用虛函數這個機制來實現多態的了

下面,我將分別說明“無覆蓋”和“有覆蓋”時的虛函數表的樣子。沒有覆蓋父類的虛函數是毫無意義的。我之所以要講述沒有覆蓋的情況,主要目的是為了給一個對比。在比較之下,我們可以更加清楚地知道其內部的具體實現。

無虛數覆蓋

下面,再讓我們來看看繼承時的虛函數表是什么樣的。假設有如下所示的一個繼承關系:

詳解C++ 多態的實現及原理

請注意,在這個繼承關系中,子類沒有重載任何父類的函數。那么,在派生類的實例中,Derive d; 的虛函表:

詳解C++ 多態的實現及原理

我們可以看到下面幾點:

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

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

有虛數覆蓋

覆蓋父類的虛函數是很顯然的事情,不然,虛函數就變得毫無意義。下面,我們來看一下,如果子類中有虛函數重載了父類的虛函數,會是一個什么樣子?假設,我們有下面這樣的一個繼承關系。

詳解C++ 多態的實現及原理

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

詳解C++ 多態的實現及原理

我們從表中可以看到下面幾點,

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

2)沒有被覆蓋的函數依舊。

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

Base *b = new Derive();

b->f();

由b所指的內存中的虛函數表的f()的位置已經被Derive::f()函數地址所取代,于是在實際調用發生時,是Derive::f()被調用了。這就實現了多態。

總結

以上所述是小編給大家介紹的c++語言虛函數實現多態的原理,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

牡丹江市| 平和县| 弥渡县| 横峰县| 福贡县| 繁昌县| 运城市| 堆龙德庆县| 宜宾县| 昌乐县| 全南县| 香港| 久治县| 金乡县| 阿瓦提县| 肃宁县| 京山县| 霍林郭勒市| 胶州市| 安福县| 西林县| 百色市| 潢川县| 新蔡县| 靖安县| 时尚| 定边县| 鹤庆县| 厦门市| 阜宁县| 阜城县| 白银市| 胶州市| 贺兰县| 抚顺县| 德令哈市| 凤台县| 广灵县| 华亭县| 洪泽县| 清远市|