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

溫馨提示×

溫馨提示×

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

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

帶你了解C++ 中的虛函數

發布時間:2020-11-03 18:37:05 來源:億速云 閱讀:154 作者:Leah 欄目:開發技術

本篇文章給大家分享的是有關帶你了解C++ 中的虛函數,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

先從對象大小開始

假設我們有如下代碼,假設 int 占 4 字節,指針占 4 字節。

#include "stdafx.h"
#include "stdlib.h"
#include "stddef.h"

class CBase
{
public:
  virtual void VFun1() { printf(__FUNCTION__ "\n"); }
  virtual void VFun2() { printf(__FUNCTION__ "\n"); }
  virtual ~CBase() { printf(__FUNCTION__ "\n"); }
  int data;
};

class CDerived : public CBase
{
public:
  virtual void VFunNew() { printf(__FUNCTION__ "\n"); }
  virtual void VFun1() override { printf(__FUNCTION__ "\n"); }
  virtual ~CDerived() override { printf(__FUNCTION__ "\n"); }
};

int _tmain(int argc, _TCHAR* argv[])
{
  printf("sizeof CBase is: %d, offset of data is %d\n",
      sizeof(CBase), offsetof(CBase, data));
  system("pause");

  CBase* pBase = new CDerived();
  pBase->VFun1();
  pBase->VFun2();
  system("pause");
  return 0;
}

輸出結果如下圖:

帶你了解C++ 中的虛函數

有沒有覺得意外?從類定義可知,data 占 4 字節,那另外的 4 字節是哪里來的呢?data 的偏移值不應該是 0 嗎?為什么是 4 呢?

內存布局

如果一個類有虛函數,編譯器會自動為這個類型的對象在頭部增加一個虛表指針(vftable),指向虛函數表。虛函數表中存放著一個個的虛函數。

CBaseCDerived 類對象的內存布局如下:

帶你了解C++ 中的虛函數

注意:虛函數表中索引為 -1 的地方指向了跟動態類型轉換相關的信息。

虛表指針的初始化

vftable 是在類的構造函數中初始化的。可以在 IDA 中分別查看 CBase 類 和 CDerived 類的構造函數的反匯編代碼。

CBase 構造函數的反匯編代碼如下(關鍵部分已注釋):

帶你了解C++ 中的虛函數

由反匯編代碼可知, CBase 的構造函數會把 CBase 對象開始的位置(存放虛表指針)設置為 CBase::vftable

CDerived 構造函數的反匯編代碼如下(關鍵部分已注釋):

帶你了解C++ 中的虛函數

由反匯編代碼可知, CDerived 的構造函數會先調用 CBase 的構造函數進行基類部分的初始化,在 CBase 構造函數的內部把 CDerived 對象開始的位置設置為 CBase::vftable,然后調用自身的初始化部分,會把 CDerived::vftable 的地址放到對象開始的位置,從而替換掉了 CBase 類的虛表指針。

虛函數表的內容

了解完了虛表指針的初始化過程,再來看看 vftable 里面都有哪些內容。

可以雙擊 ??_7CBase@@6B@ (或者直接按回車)跳轉到虛表所在的地方。如下圖:

帶你了解C++ 中的虛函數

說明:上側是 CBase 類的虛表內容,下側是 CDerived 類的虛表內容。

請注意圖片上側黃色高亮部分,也就是 vftable[-1] 的地方,是跟動態類型轉換相關的信息,后面有機會介紹。

虛函數調用

理解了類對象的內存布局及虛函數表之后,再理解虛函數的調用過程就比較簡單了。

有些 C++ 基礎的小伙伴兒都知道本例中的輸出結果應該如下圖所示:

帶你了解C++ 中的虛函數

直接看一下 pBase->VFun1() pBase->VFun2() 對應的反匯編代碼就應該明白一切了。如下圖:

帶你了解C++ 中的虛函數

因為 pBase 指向的實際是 CDerived 類型的對象,所以虛表是 CDerived 類的。如下圖所示

帶你了解C++ 中的虛函數

經過以上的分析,輸出結果合情合理。

說明

本文只是拿了一個最最簡單的例子做演示。像多重繼承,虛繼承等比較復雜的情況,感興趣的小伙伴可以自行研究。

雖然這個例子很簡單,但是背后的機理值得了解清楚,非常有用。比如,當庫中的接口與庫頭文件不匹配的時候,很可能莫名其妙的就崩潰了。這時可以通過查看指針對應的虛表的內容來查看庫中的虛函數都有哪些,跟頭文件對比后就可以比較準確的判斷是否是庫不匹配的問題。還可以根據虛表的內容,猜測出基類指針指向的具體的子類對象的類型。

可以在 windbg 中使用 dps 命令快速打印,如下圖:

帶你了解C++ 中的虛函數

總結

  • 虛表指針是在類的構造函數中初始化的,相應的代碼由編譯器自動生成。
  • 在生成調用虛函數的代碼的時候,并沒有直接把虛函數地址寫死,而是通過虛表進行調用,多了一層間接層。
  • Any problem in computer science can be solved by anther layer of indirection. (計算機科學領域的任何問題都可以通過增加一個間接的中間層來解決)

注意:如果通過對象調用虛函數,會是另外一種情況,因為不存在多態,直接使用函數低級進行調用就可以了。感興趣的小伙伴兒可以自行實驗。

以上就是帶你了解C++ 中的虛函數,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

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

AI

崇左市| 柘城县| 化德县| 三都| 玛沁县| 绵竹市| 定州市| 贞丰县| 通榆县| 楚雄市| 株洲县| 桐乡市| 松潘县| 新和县| 三门县| 天等县| 维西| 扎鲁特旗| 威远县| 清水河县| 城口县| 木兰县| 新泰市| 县级市| 柏乡县| 垦利县| 拉萨市| 灵寿县| 沁水县| 五常市| 历史| 新源县| 威信县| 泌阳县| 建昌县| 金昌市| 佛冈县| 黎城县| 开平市| 佛学| 洞头县|