C/C++雜記 虛函數的完成的根本道理(圖文)。本站提示廣大學習愛好者:(C/C++雜記 虛函數的完成的根本道理(圖文))文章只能為提供參考,不一定能成為您想要的結果。以下是C/C++雜記 虛函數的完成的根本道理(圖文)正文
1. 概述
簡略地說,每個含有虛函數(不管是其自己的,照樣繼續而來的)的類都至多有一個與之對應的虛函數表,個中寄存著該類一切的虛函數對應的函數指針。例:
個中:
B的虛函數表中寄存著B::foo和B::bar兩個函數指針。
D的虛函數表中寄存的既有繼續自B的虛函數B::foo,又有重寫(override)了基類虛函數B::bar的D::bar,還有新增的虛函數D::quz。
提醒:為了描寫便利,本文在商量對象內存結構時,將疏忽內存對齊對結構的影響。
2. 虛函數表結構進程
從編譯器的角度來講,B的虛函數表很好結構,D的虛函數表結構進程絕對龐雜。上面給出了結構D的虛函數表的一種方法(僅供參考):
提醒:該進程是由編譯器完成的,是以也能夠說:虛函數調換進程產生在編譯時。
3. 虛函數挪用進程
以上面的法式為例:
編譯器只曉得pb是B*類型的指針,其實不曉得它指向的詳細對象類型 :pb能夠指向的是B的對象,也能夠指向的是D的對象。
但關於“pb->bar()”,編譯時可以或許肯定的是:此處operator->的另外一個參數是B::bar(由於pb是B*類型的,編譯器以為bar是B::bar),而B::bar和D::bar在各自虛函數表中的偏移地位是相等的。
不管pb指向哪一種類型的對象,只需可以或許肯定被調函數在虛函數中的偏移值,待運轉時,可以或許肯定詳細類型,並能找到響應vptr了,就可以找出真正應當挪用的函數。
提醒:自己曾在“C/C++雜記:深刻懂得數據成員指針、函數成員指針”一文中提到:虛函數指針中的ptr部門為虛函數表中的偏移值(以字節為單元)加1。
B::bar是一個虛函數指針, 它的ptr部門內容為9,它在B的虛函數表中的偏移值為8(8+1=9)。
當法式履行到“pb->bar()”時,曾經可以或許斷定pb指向的詳細類型了:
假如pb指向B的對象,可以獲得到B對象的vptr,加上偏移值8((char*)vptr + 8),可以找到B::bar。
假如pb指向D的對象,可以獲得到D對象的vptr,加上偏移值8((char*)vptr + 8) ,可以找到D::bar。
假如pb指向其它類型對象...同理...
4. 多重繼續
當一個類繼續多個類,且多個基類都有虛函數時,子類對象中將包括多個虛函數表的指針(即多個vptr),例:
個中:D本身的虛函數與B基類共用了統一個虛函數表,是以也稱B為D的主基類(primary base class)。
虛函數調換進程與後面描寫相似,只是多了一個虛函數表,多了一次拷貝和調換的進程。
虛函數的挪用進程,與後面描寫根本相似,差別在於基類指針指向的地位能夠不是派生類對象的肇端地位,以以下面的法式為例:
5. 菱形繼續
本文不評論辯論菱形繼續的情況,小我認為:菱形繼續的龐雜度弘遠於它的應用價值,這也是C++讓人又愛又恨的緣由之一。
假如想要深刻研討,可以參考:Itanium C++ ABI。