C/C++多態及其實現原理

C/C++多態及其實現原理

多態的介紹

多態含義爲一個事物有多種形態。在C ++程序設計中,多態性是指具有不同功能的函數可以用同一個函數名,這樣就可以用一個函數名調用不同內容的函數。一般來說多態分爲兩種:

  • 靜態多態:也稱爲編譯時多態,主要包括參數多態,過載多態和強制多態。參數多態:採用參數化模板,通過給出不同的類型參數,使得一個結構有多種類型。如 C++語言中的函數模板和類模板屬於參數多態。參數多態又叫靜態多態,它的執行速度快,異常少,調用在編譯時已經確定。過載多態:同一個名字在不同的上下文中所代表的含義不同。典型的例子是運算符重載和函數重載。強制多態:編譯程序通過語義操作,把操作對象的類型強行加以變換,以符合函數或操作符的要求。程序設計語言中基本類型的大多數操作符,在發生不同類型的數據進行混合運算時,編譯程序一般都會進行強制多態。程序員也可以顯示地進行強制多態的操作。如 int+double,編譯系統一般會把 int 轉換爲 double,然後執行 double+double 運算,這個int->double 的轉換,就實現了強制多態,即可是隱式的,也可顯式轉換。強制多態屬於靜態多態。
     
  • 動態多態:也稱運行時多態,主要包括:包含多態。包含多態的基礎是虛函數。主要是通過類的繼承和虛函數來實現,當基類和子類擁有同名同參同返回的方法,且該方法聲明爲虛方法,當基類對象,指針,引用指向的是派生類的對象的時候,基類對象,指針,引用在調用基類的方法,實際上調用的是派生類方法。

重載多態和強制多態是指特定多態, 重載多態和強制多態稱爲特殊多態性,用來刻畫語義上無關聯的類型間的關係;參數多態和包含多態是指通用多態,類型參數化多態和包含多態稱爲一般多態性,用來系統地刻畫語義上相關的一組類型。

靜態多態實現

靜態多態靠編譯器來實現,簡單來說就是編譯器對原來的函數名進行修飾。可以根據函數參數的類型,個數,以及修飾函數const,這就使得函數可以重載。同理,模板也是可以實現的,針對不同類型的實參來產生對應的特化的函數,通過增加修飾,使得不同的類型參數的函數得以區分。

動態多態的實現

動態多態靠運行時的類型檢查,從而來進行函數的綁定。聲明一個類時,如果類中有虛方法,則自動在類中增加一個虛函數指針,該指針指向的是一個虛函數表,虛函數表中存着每個虛函數真正對應的函數地址。動態多態採用一種延遲綁定技術,普通的函數調用,在編譯期間就已經確定了調用的函數的地址,所以無論怎樣調用,總是那個函數,但是擁有虛函數的類,在調用虛函數時,首先去查虛函數表,然後在確定調用的是哪一個函數,所以,調用的函數是在運行時纔會確定的。

  • 虛表指針初始化問題

當創建子類對象時,編譯器的執行順序其實是這樣的:

  1. 對象在創建時,由編譯器對 vptr 進行初始化
  2. 子類的構造會先調用父類的構造函數,這個時候 vptr 會先指向父類的虛函數表
  3. 子類構造的時候,vptr 會再指向子類的虛函數表
  4. 對象的創建完成後,vptr 最終的指向才確定
  • 虛函數表的構成

具體的詳細細節見https://blog.csdn.net/wenqiang1208/article/details/53148486

https://www.cnblogs.com/longcnblogs/archive/2017/10/09/7642951.html

  • 無覆蓋的公有單繼承:虛函數按聲明順序存在於虛表中; 在派生類中,前面是基類的虛函數,後面是派生類的虛函數。
  • 有覆蓋的公有單繼承:先拷貝基類的虛表;如果派生類重寫了基類的虛函數,則修改同位置的基類虛函數;最後面是生類新定義的虛函數。

單繼承的派生類的大小:虛表指針+ 基類的數據成員 + 派生類的成員

  • 多重繼承:

多重繼承派生類的大小:(例如有兩個父類)——基類1的虛表指針+基類1的成員變量+基類2的虛表指針+基類2的成員變量+子類成員變量

如果派生類有新定義的虛函數,則存放在繼承順序第一的基類續表的最後面。

  • 菱形繼承

如果派生類有新的虛函數,則添加在第一繼承順序的續表最後面。菱形繼承存在二義性,由於直接父類都繼承了祖父類的成員變量——導致修改一處,而另外一處沒有修改(引起數據不一致性)。

  • 虛繼承中的單繼承

1. 沒有構造函數和析構函數(少中間的0——所佔的字節),派生類有新的虛函數

2. 沒有構造函數和析構函數(少中間的0——所佔的字節),派生類沒有新的虛函數

3. 有構造函數和析構函數(多中間的0——所佔的字節),派生類有新的虛函數

虛繼承中派生類的構造函數做了什麼

  • 虛繼承中的多繼承

  沒有考慮構造函數或析構函數 ,派生類定義了新虛函數

  • 虛繼承中的菱形繼承

沒有考慮構造函數或析構函數 ,派生類定義了新虛函數

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章