考虑下面的C ++代码:
class A
{
public:
virtual void f()=0;
};
int main()
{
void (A::*f)()=&A::f;
}
如果我不得不猜测,我会说,&A :: F IN此背景下,将意味着“的的实现F()的地址”,因为有定期的成员函数和虚成员函数指针之间没有明确的分离 - 。 并且由于没有实现F(),这将是一个编译错误。 然而,事实并非如此。
不仅如此。 下面的代码:
void (A::*f)()=&A::f;
A *a=new B; // B is a subclass of A, which implements f()
(a->*f)();
实际上将调用B :: F。
它是如何发生的呢?
以下是有关成员函数指针的方式太多的信息。 有一个关于虚函数的一些东西在“乖编译”,虽然IIRC当我读到的文章我是略读的那部分,由于物品实际上是关于用C实现委托++。
http://www.codeproject.com/KB/cpp/FastDelegate.aspx
简短的回答是,它依赖于编译器,但一种可能性是该成员函数指针作为含有一个指向“咚”的功能,这使得虚拟呼叫的结构来实现。
它的工作原理,因为标准说,这应该是如何发生的。 我做了一些测试与海湾合作委员会,它原来的虚函数,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
-的那些两个函数的虚拟表条目的字节偏移。 它遵循安腾C ++ ABI, 它指定 。
我不能完全肯定,但我认为这只是常规的多态行为。 我认为, &A::f
实际上意味着在类的虚函数表函数指针的地址,这就是为什么你没有得到一个编译器错误。 在虚函数表的空间仍然分配,而且是你实际上又回到了位置。
这是有道理的,因为派生类基本覆盖这些值与指针的功能。 这就是为什么(a->*f)()
工作在你的第二个例子- f
会引用在派生类中实现虚函数表。
文章来源: Pointers to virtual member functions. How does it work?