程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C/C++雜記 虛函數的完成的根本道理(圖文)

C/C++雜記 虛函數的完成的根本道理(圖文)

編輯:關於C++

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。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved