簡體   English   中英

指向成員函數的指針執行虛擬調度?

[英]Pointer-to-member-function performs virtual dispatch?

我嘗試執行以下代碼。

#include <iostream>

class Base
{
public:
    virtual void func()
    {
        std::cout<<"Base called"<<std::endl;
    }
};

class Derived: public Base
{
public:
    virtual void func()  override
    {
        std::cout<<"Derived called"<<std::endl;
    }
};

int main()
{
    void (Base::*func_ptr)()=&Base::func; //Yes, the syntax is very beautiful.
    Base* bptr=new Derived();
    (bptr->*func_ptr)();
}

我的預期輸出是Base called 然而,相反,輸出是

Derived called

這讓我感到驚訝,因為我認為func_ptr應該只能看到Base成員(因為我認為func_ptr不是通過_vptr訪問成員函數,而是通過函數地址本身。

我想知道,在這種情況下如何進行虛擬分派(如何訪問虛擬表),以及在 C++ 標准中定義此行為的位置(我找不到任何東西)?

參考[expr.call] ,特別是這里

[如果選擇的函數是虛擬的],它在對象表達式的動態類型中的最終覆蓋被調用; 這樣的調用稱為虛函數調用

無論是通過指針調用函數還是通過類成員訪問調用函數都是一樣的( ref ); 為虛函數調用的實際函數最終取決於它被調用的對象的實際類型

[class.virtual]下標准中的一些(非規范性)注釋大致相同:

[注3:虛函數調用的解釋取決於調用它的對象的類型(動態類型)

[注 4:[...] 虛擬函數調用依賴於特定對象來確定要調用哪個函數。


如果你想知道虛函數調度是如何發生的,你需要尋找一個具體的實現,因為如何不是標准化的。

(我真的很喜歡這篇文章虛擬表的基本概覽,它展示了一種可以使用 C 實現它的可能方法)

  1. 你的理解是錯誤的。
  2. 這是一個實現細節。 不同的編譯器可能會以不同的方式實現它。 如有疑問,請查看組件 在這個特定的編譯器中,它實際上非常聰明。 如果成員指針中存儲的值是偶數,則它是一個直函數指針(所有函數都位於偶數地址)。 如果是奇數,則是 vtable 中的偏移量加一。 所有 vtable 偏移量也是偶數,因此要到達實際指針,它會減 1。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM