欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++ 中的虛函數(shù)表及虛函數(shù)執(zhí)行原理詳解

 更新時間:2021年03月07日 10:03:44   作者:Er_HU  
這篇文章主要介紹了C++ 中的虛函數(shù)表及虛函數(shù)執(zhí)行原理詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

為了實現(xiàn)虛函數(shù),C++ 使用了虛函數(shù)表來達到延遲綁定的目的。虛函數(shù)表在動態(tài)/延遲綁定行為中用于查詢調(diào)用的函數(shù)。

盡管要描述清楚虛函數(shù)表的機制會多費點口舌,但其實其本身還是比較簡單的。

首先,每個包含虛函數(shù)的類(或者繼承自的類包含了虛函數(shù))都有一個自己的虛函數(shù)表。這個表是一個在編譯時確定的靜態(tài)數(shù)組。虛函數(shù)表包含了指向每個虛函數(shù)的函數(shù)指針以供類對象調(diào)用。

其次,編譯器還在基類中定義了一個隱藏指針,我們稱為 *__vptr,*__vptr 是在類實例創(chuàng)建時自動設(shè)置的,以指向類的虛函數(shù)表。*__vptr 是一個真正的指針,這和 *this 指針不同,*this 指針實際是一個函數(shù)參數(shù),使編譯器來達到自引用的目的。

結(jié)果就是,每個類對象都會多分配一個指針的大小,并且 *__vptr 是被派生類繼承的。

如果你不清楚這些組件是怎么配合運作的,看下面的例子:

class Base
{
public:
  virtual void function1() {};
  virtual void function2() {};
};
 
class D1: public Base
{
public:
  virtual void function1() {};
};
 
class D2: public Base
{
public:
  virtual void function2() {};
};

因為這里有 3 個類,編譯器會創(chuàng)建 3 個虛函數(shù)表。

然后編譯器會在使用了虛函數(shù)的最上層基類中定義一個隱藏指針。盡管這個過程編譯器會自動處理,但我們還是通過下面的例子來說明指針添加的位置:

class Base
{
public:
  FunctionPointer *__vptr;
  virtual void function1() {};
  virtual void function2() {};
};
 
class D1: public Base
{
public:
  virtual void function1() {};
};
 
class D2: public Base
{
public:
  virtual void function2() {};
};

*__vptr 在類對象創(chuàng)建的時候會設(shè)置成指向類的虛函數(shù)表。例如,類型 Base 被實例化的時候,*__vptr 就指向 Base 的虛函數(shù)表。類型 D1 或者 D2 被實例化的時候,*__vptr 就指向 D1 或者 D2 的虛函數(shù)表。

現(xiàn)在我們來看下虛函數(shù)表是怎么創(chuàng)建的。因為示例中每個類僅有 2 個虛函數(shù),所以每個虛函數(shù)表會存放兩個函數(shù)指針(分別指向 function1() 和 function2())。

Base 對象的虛函數(shù)表最簡單。Base 對象只能訪問 Base 類型的成員,不能訪問 D1 或者 D2 的函數(shù)。所以 Base 的虛函數(shù)表中的兩個指針分別指向 Base::function1() 和 Base::function2()。

D1 的虛函數(shù)表稍復(fù)雜點,D1 對象能夠訪問 D1 以及 Base 的成員。D1 重寫了 function1(),但沒有重寫 function2(),所以 D1 的虛函數(shù)表中的兩個指針分別指向 D1::function1() 和 Base::function2()。

D2 的虛函數(shù)表同理 D1,包含了分別指向 Base::function1() 和 D2::function2() 的指針。

考慮如果創(chuàng)建 D1 對象時會發(fā)生什么:

int main()
{
  D1 d1;
}

因為 d1 是 D1 類型對象,d1 有它自己的 *__vptr 指向 D1 類型的虛函數(shù)表。

現(xiàn)在創(chuàng)建一個 Base 類型指針 *dPtr 指向 d1:

int main()
{
  D1 d1;
  Base *dPtr = &d1;
 
  return 0;
}

重點:

因為 dPtr 是 Base 類型指針,它只指向 d1 對象的 Base 類型部分(即,指向 d1 對象中的 Base 子對象),而 *__vptr 也在 Base 類型部分。所以 dPtr 可以訪問 Base 類型部分中的 *__vptr。同時,這里注意,dPtr->__vptr 指向的是 D1 的虛擬函數(shù)表,這是在 d1 初始化時就確定的。所以結(jié)果,盡管 dPtr 是 Base 類型指針,但它能夠訪問 D1 的虛函數(shù)表。

因此,當有調(diào)用 dPtr->function1() 時,發(fā)生了什么?

int main()
{
  D1 d1;
  Base *dPtr = &d1;
  dPtr->function1();
 
  return 0;
}

首先,程序識別到 function1() 是一個虛函數(shù)。

其次,程序使用 dPtr->__vptr 獲取到了 D1 的虛函數(shù)表。

然后,它在 D1 的虛函數(shù)表中尋找可以調(diào)用的 function1() 版本,這里是 D1::function1()。

因此,dPtr->function1() 實際調(diào)用了 D1::function1()。

通過虛函數(shù)表,編譯器和程序能夠確定調(diào)用什么版本的虛函數(shù),盡管使用的是指向/引用基類的指針或者引用。

調(diào)用虛函數(shù)會比調(diào)用非虛函數(shù)更慢,有以下幾個原因:

  • 必須使用 *__vptr 獲取正確的虛函數(shù)。
  • 必須建立虛函數(shù)表的索引來獲取想要調(diào)用的函數(shù)。
  • 調(diào)用找到的函數(shù)。

結(jié)果就是必須進行三次操作才能完成對函數(shù)的調(diào)用。但是對于現(xiàn)代計算機系統(tǒng),這些額外操作增加的時間幾乎可以忽略不計。

另外,每個使用虛函數(shù)表的類都有 *__vptr 指針,從而每個類對象都會多一個指針的空間。虛函數(shù)很強大,但是它確實產(chǎn)生了性能開銷。

到此這篇關(guān)于C++ 中的虛函數(shù)表及虛函數(shù)執(zhí)行原理詳解的文章就介紹到這了,更多相關(guān)C++ 虛函數(shù)表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++動態(tài)加載so/dll庫的實現(xiàn)

    C++動態(tài)加載so/dll庫的實現(xiàn)

    本文主要介紹了C++動態(tài)加載so/dll庫的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • 詳解C++編程中類模板的相關(guān)使用知識

    詳解C++編程中類模板的相關(guān)使用知識

    這篇文章主要介紹了詳解C++編程中類模板的相關(guān)使用知識,包括函數(shù)的參數(shù)類型替換等方法,需要的朋友可以參考下
    2015-09-09
  • C語言中scanf的用法舉例

    C語言中scanf的用法舉例

    本節(jié)介紹輸入函數(shù)?scanf?的用法,scanf?和?printf?一樣,非常重要,而且用得非常多,所以一定要掌握,這篇文章主要介紹了C++中scanf的用法舉例,需要的朋友可以參考下
    2022-11-11
  • C/C++ memset方法的誤區(qū)

    C/C++ memset方法的誤區(qū)

    memset 作為對內(nèi)存初始化的函數(shù),還是有不少坑和誤區(qū)的,今天就來對這個函數(shù)作一個總結(jié)。避免后期使用不當踩入坑,需要的朋友可以參考下
    2021-04-04
  • C++實現(xiàn)獲取郵件中的附件

    C++實現(xiàn)獲取郵件中的附件

    這篇文章主要為大家詳細介紹了如何通過C++實現(xiàn)獲取郵件文件中的附件,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • C語言實現(xiàn)一個簡單的掃雷游戲

    C語言實現(xiàn)一個簡單的掃雷游戲

    掃雷是電腦上很經(jīng)典的游戲,特意去網(wǎng)上玩了一會,幾次調(diào)試之后,發(fā)現(xiàn)這個比三子棋要復(fù)雜一些,尤其是空白展開算法上和堵截玩家有的一拼,與實際游戲差別較大,不能使用光標,下面來詳解每一步分析
    2021-10-10
  • 純C語言:貪心Prim算法生成樹問題源碼分享

    純C語言:貪心Prim算法生成樹問題源碼分享

    這篇文章主要介紹了貪心Prim算法生成樹問題源碼,有需要的朋友可以參考一下
    2014-01-01
  • C++ 中CloseHandle 函數(shù)--關(guān)閉一個句柄

    C++ 中CloseHandle 函數(shù)--關(guān)閉一個句柄

    這篇文章主要介紹了C++ 中CloseHandle 函數(shù)--關(guān)閉一個句柄的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • C語言詳解鏈式隊列與循環(huán)隊列的實現(xiàn)

    C語言詳解鏈式隊列與循環(huán)隊列的實現(xiàn)

    隊列(Queue)與棧一樣,是一種線性存儲結(jié)構(gòu),它具有如下特點:隊列中的數(shù)據(jù)元素遵循“先進先出”(First In First Out)的原則,簡稱FIFO結(jié)構(gòu)。在隊尾添加元素,在隊頭刪除元素,本篇來講解鏈式隊列與循環(huán)隊列的實現(xiàn)
    2022-04-04
  • C++中數(shù)組作為函數(shù)參數(shù)傳入的幾種方式代碼示例

    C++中數(shù)組作為函數(shù)參數(shù)傳入的幾種方式代碼示例

    數(shù)組元素和數(shù)組名都可以作為函數(shù)的參數(shù)以實現(xiàn)函數(shù)間數(shù)據(jù)的傳遞和共享,下面這篇文章主要給大家介紹了關(guān)于C++中數(shù)組作為函數(shù)參數(shù)傳入的幾種方式,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-06-06

最新評論