指向成员函数的指针执行虚拟调度?
最近我尝试运行以下代码。
#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]下标准中的一些(非规范性)注释大致相同:
如果你想知道虚函数调度是如何发生的,你需要寻找一个具体的实现,因为如何不是标准化的。
(我真的很喜欢这篇文章虚拟表的基本概览,它展示了一种可以使用 C 实现它的可能方法)