1. 程式人生 > >c++多態實現原理

c++多態實現原理

c++編譯器 anim 被調用 虛指針 編譯 基類 綁定 確定調用 包括

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

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

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

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

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

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

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

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

實現過程:

編譯器在編譯的時候,發現Father類中有虛函數,此時編譯器會為每個包含虛函數的類創建一個虛表(即 vtable),該表是一個一維數組,在這個數組中存放每個虛函數的地址,

那麽如何定位虛表呢?編譯器另外還為每個對象提供了一個虛表指針(即vptr),這個指針指向了對象所屬類的虛表

在程序運行時,根據對象的類型去初始化vptr,從而讓vptr正確的指向所屬類的虛表,從而在調用虛函數時,就能夠找到正確的函數。

要註意:

1.對於虛函數調用來說,每一個對象內部都有一個虛表指針,該虛表指針被初始化為本類的虛表。所以在程序中,不管你的對象類型如何轉換,但該對象內部的虛表指針是固定的,所以呢,才能實現動態的對象函數調用,這就是C++多態性實現的原理。

2.正是由於每個對象調用的虛函數都是通過虛表指針來索引的,也就決定了虛表指針的正確初始化是非常重要的,換句話說,在虛表指針沒有正確初始化之前,我們不能夠去調用虛函數,那麽虛表指針是在什麽時候,或者什麽地方初始化呢?

  答案是在構造函數中進行虛表的創建和虛表指針的初始化,在構造子類對象時,要先調用父類的構造函數,此時編譯器只“看到了”父類,並不知道後面是否還有繼承者,它初始化父類對象的虛表指針,該虛表指針指向父類的虛表,當執行子類的構造函數時,子類對象的虛表指針被初始化,指向自身的虛表。

 總結(基類有虛函數的):

  1:每一個類都有虛表

  2:虛表可以繼承,如果子類沒有重寫虛函數,那麽子類虛表中仍然會有該函數的地址,只不過這個地址指向的是基類的虛函數實現,如果基類有3個虛函數,那麽基類的虛表中就有三項(虛函數地址),派生類也會虛表,至少有三項,如果重寫了相應的虛函數,那麽虛表中的地址就會改變,指向自身的虛函數實現,如果派生類有自己的虛函數,那麽虛表中就會添加該項。

  3:派生類的虛表中虛地址的排列順序和基類的虛表中虛函數地址排列順序相同。

  這就是c++中的多態性,當c++編譯器在編譯的時候,發現Father類的Say()函數是虛函數,這個時候c++就會采用晚綁定技術,也就是編譯時並不確定具體調用的函數,而是在運行時,依據對象的類型來確認調用的是哪一個函數,這種能力就叫做c++的多態性,我們沒有在Say()函數前加virtual關鍵字時,c++編譯器就確定了哪個函數被調用,這叫做早期綁定。

  c++的多態性就是通過晚綁定技術來實現的。

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

  虛函數是在基類中定義的,目的是不確定它的派生類的具體行為,例如:

  定義一個基類:class Animal //動物,它的函數為breathe()

  再定義一個類class Fish //魚。它的函數也為breathe()

  再定義一個類class Sheep //羊,它的函數也為breathe()

將Fish,Sheep定義成Animal的派生類,然而Fish與Sheep的breathe不一樣,所以基類不能確定該如何定義breathe,所以在基類中只定義了一個virtual breathe,它是一個空的虛函數,具體的函數在子類中分別定義,程序一般運行時,找到類,如果它有基類,再找到它的基類,最後運行的是基類中的函數,這時,它在基類中找到的是virtual標識的函數,它就會再回到子類中找同名函數,派生類也叫子類,基類也叫父類,這就是虛函數的產生,和類的多態性的體現。

  這裏的多態性是指類的多態性。

  函數的多態性是指一個函數被定義成多個不同參數的函數。當你調用這個函數時,就會調用不同的同名函數。

一般情況下(不涉及虛函數),當我們用一個指針/引用調用一個函數的時候,被調用的函數是取決於這個指針/引用的類型。

當設計到多態性的時候,采用了虛函數和動態綁定,此時的調用就不會在編譯時候確定而是在運行時確定。不在單獨考慮指針/引用的類型而是看指針/引用的對象的類型來判斷函數的調用,根據對象中虛指針指向的虛表中的函數的地址來確定調用哪個函數

c++多態實現原理