![](/img/trans.png)
[英]Virtual member functions and std::tr1::function: How does this work?
[英]Pointers to virtual member functions. How does it work?
考慮以下 C++ 代碼:
class A
{
public:
virtual void f()=0;
};
int main()
{
void (A::*f)()=&A::f;
}
如果我不得不猜測,我會說 &A::f 在這個上下文中的意思是“A 的 f() 實現的地址”,因為在指向常規成員函數和虛擬成員函數的指針之間沒有明確的分隔. 由於 A 沒有實現 f(),這將是一個編譯錯誤。 然而,事實並非如此。
而且不僅如此。 以下代碼:
void (A::*f)()=&A::f;
A *a=new B; // B is a subclass of A, which implements f()
(a->*f)();
實際上會調用 B::f。
它是如何發生的?
它之所以有效,是因為標准說它應該是這樣發生的。 我用 GCC 做了一些測試,結果是對於虛擬函數,GCC 以字節為單位存儲相關函數的虛擬表偏移量。
struct A { virtual void f() { } virtual void g() { } };
int main() {
union insp {
void (A::*pf)();
ptrdiff_t pd[2];
};
insp p[] = { { &A::f }, { &A::g } };
std::cout << p[0].pd[0] << " "
<< p[1].pd[0] << std::endl;
}
該程序輸出1 5
- 這兩個函數的虛擬表條目的字節偏移量。 它遵循Itanium C++ ABI , 它指定.
這里有太多關於成員函數指針的信息。 在“The Well-Behaved Compilers”下有一些關於虛函數的內容,盡管 IIRC 在我閱讀這篇文章時我正在略讀那部分,因為這篇文章實際上是關於在 C++ 中實現委托的。
http://www.codeproject.com/KB/cpp/FastDelegate.aspx
簡短的回答是它取決於編譯器,但一種可能性是成員函數指針被實現為一個結構,其中包含一個指向“thunk”函數的指針,該函數進行虛擬調用。
我不完全確定,但我認為這只是常規的多態行為。 我認為&A::f
實際上表示類的 vtable 中函數指針的地址,這就是為什么您沒有收到編譯器錯誤的原因。 vtable 中的空間仍然分配,這就是您實際返回的位置。
這是有道理的,因為派生類本質上用指向它們的函數的指針覆蓋了這些值。 這就是(a->*f)()
在您的第二個示例中起作用的原因 - f
引用了在派生類中實現的 vtable。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.