日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

通过对象指针的方式强行指定到子类_C++中的虚指针与虚函数表

發布時間:2024/9/27 c/c++ 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 通过对象指针的方式强行指定到子类_C++中的虚指针与虚函数表 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? 最近在逛B站的時候發現有候捷老師的課程,如獲至寶。因此,跟隨他的講解又復習了一遍關于C++的內容,收獲也非常的大,對于某些模糊的概念及遺忘的內容又有了更深的認識。

以下內容是關于虛函數表、虛函數指針,而C++中的動態綁定實現和這兩個內容是分不開的。

虛函數表、虛指針

? 當一個類在實現的時候,如果存在一個或以上的虛函數時,那么這個類便會包含一張虛函數表。而當一個子類繼承并重載了基類的虛函數時,它也會有自己的一張虛函數表。當我們在設計類的時候,如果把某個函數設置成虛函數時,也就表明我們希望子類在繼承的時候能夠有自己的實現方式;如果我們明確這個類不會被繼承,那么就不應該有虛函數的出現。

下面是某個基類A的實現:

class

? 從下圖中可以看到該類在內存中的存放形式,對于虛函數的調用是通過查虛函數表來進行的,每個虛函數在虛函數表中都存放著自己的一個地址,而如何在虛函數表中進行查找,則是通過虛指針來調用,在內存結構中它一般都會放在類最開始的地方,而對于普通函數則不需要通過查表操作。這張虛函數表是什么時候被創建的呢?它是在編譯的時候產生,否則這個類的結構信息中也不會插入虛指針的地址信息。

以下例子包含了繼承關系:

class

以上三個類在內存中的排布關系如下圖所示:

  • 對于非虛函數,三個類中雖然都有一個叫 func2 的函數,但他們彼此互不關聯,因此都是各自獨立的,不存在重載一說,在調用的時候也不需要進行查表的操作,直接調用即可。
  • 由于子類B和子類C都是繼承于基類A,因此他們都會存在一個虛指針用于指向虛函數表。注意,假如子類B和子類C中不存在虛函數,那么這時他們將共用基類A的一張虛函數表,在B和C中用虛指針指向該虛函數表即可。但是,上面的代碼設計時子類B和子類C中都有一個虛函數 vfunc1,因此他們就需要各自產生一張虛函數表,并用各自的虛指針指向該表。由于子類B和子類C都對 vfunc1 作了重載,因此他們有三種不同的實現方式,函數地址也不盡相同,在使用的時候需要從各自類的虛函數表中去查找對應的 vfunc1 地址。
  • 對于虛函數 vfunc2,兩個子類都沒有進行重載操作,所以基類A、子類B和子類C將共用一個 vfunc2,該虛函數的地址會分別保存在三個類的虛函數表中,但他們的地址是相同的。
  • 從上圖可以發現,在類對象的頭部存放著一個虛指針,該虛指針指向了各自類所維護的虛函數表,再通過查找虛函數表中的地址來找到對應的虛函數。
  • 對于類中的數據而言,子類中都會包含父類的信息。如上例中的子類C,它自己擁有一個變量 m_data1,似乎是和基類中的 m_data1 重名了,但其實他們并不存在聯系,從存放的位置便可知曉。
  • 關于動態綁定

    在設計了以上三個類之后,我們就要開始對它們進行使用。

    int

    ? 假如在程序中分別創建兩個對象 a 和 b,a的創建是通過將b強制轉化為類A得來的。對于 b.vfunc1() 的調用,應該沒有太的疑問,它所調用的就是類B中的 vfunc1。而對于 a.vfunc1() 的調用,它雖然是強制轉化后的結果,但并不能改變它是一個類A對象的事實,因此這里調用的便是類A中的 vfunc1,也就是上圖中顯示綠色的函數。

    int

    ? 將程序改寫成以上內容,pa 是一個類A的指針,但它指向的是一個類B的對象。在使用pa調用 vfunc1 的時候,程序發現pa是一個指針,并且現在正在調用一個虛函數叫做 vfunc1,這時通過 pa->vptr 這個虛指針到類B的虛函數中(上圖的B vtbl)找對應的虛函數地址,找到該地址以后,就用相應的虛函數來進行調用,也就是調用上圖所示的 B::vfunc1()。

    pa是類A的指針,為什么查找的是類B的虛函數表?
    只要某一個類X包含虛函數,無論是它的父類或者它本身擁有,那么這個類的對象都會包含一個虛指針vptr,至于vptr要指向哪張表,取決于類X它本身是否含有虛函數。此處,類B中存在虛函數,那么它就會擁有自己的一張虛函數表。pa指向的是一個類B的對象,因此 p-vptr 指代的是類B中虛指針,所以它查找的是類B的虛函數表
    如何從虛函數表中查找到 vfunc1 的地址?
    虛函數表中的內容是在編譯的時候確定的,通過以下方式進行查找 (* p->vptr[n] )(p) 或者 (* (p->vptr)[n] )(p),它的解讀是:通過類對象指針p找到虛指針vptr,再查找到虛函數表中的第n個內容,并將他作為函數指針進行調用,調用時的入參是p(式子中的第二個p),而這個p就是隱藏的this指針,這里的n也是在編譯的時候確定的。int

    ? 再將程序修改成以上內容,對于 p2->vfunc1() 的調用和上文所述一致,它調用的是 B::vfunc1 函數。而對于 p1->vfunc1() 的調用,同樣通過上面的方法可知, p1->vptr 它所指向的是類A的虛函數表,因此它調用的是 A::vfunc1 函數。

    ? 通過以上內容,我們可以知道在使用基類指針調用虛函數的時候,它能夠根據所指的類對象的不同來正確調用虛函數。而這些能夠正常工作,得益于虛指針和虛函數表的引入,使得在程序運行期間能夠動態調用函數。

    動態綁定有以下三項條件要符合:

  • 使用指針進行調用
  • 指針屬于up-cast后的
  • 調用的是虛函數
  • 與動態綁定相對應的是靜態綁定,它屬于編譯的時候就確定下來的,如上文的非虛函數,他們是類對象直接可調用的,而不需要任何查表操作,因此調用的速度也快于虛函數。

    參考

  • https://www.bilibili.com/video/av48240648?p=1
  • 總結

    以上是生活随笔為你收集整理的通过对象指针的方式强行指定到子类_C++中的虚指针与虚函数表的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。