指向成员函数的指针是否执行虚拟分派?

我试图执行以下代码

\include<iostream>
阶级基础
{
公众:
虚空函数()
{
std::cout<<<<<基本函数称为<<std::endl;
}
};
派生类:公共基
{
公众:
虚拟void func()重写
{
std::cout“派生函数”称为“std::endl”;
}
};
int main()
{
void(Base::*func_ptr)(=&Base::func;//是的,语法非常漂亮。
Base*bptr=新派生的();
(bptr->*func_ptr)();
}

我的预期输出是调用的基本func。然而,结果却相反

调用了派生func

这让我很惊讶,因为我认为func_ptr应该只能看到Base成员(因为我认为func_ptr不是通过\u vptr访问成员函数,而是函数地址本身

我想知道,在这种情况下,虚拟调度是如何发生的(如何访问虚拟表),以及在C++标准中定义了什么行为(我找不到任何东西)?

具体请参见[expr.call]

[如果所选函数为虚拟函数],则调用对象表达式动态类型中的最终重写器;此类调用称为虚拟函数调用

通过指针还是通过类成员访问调用函数是相同的(ref);为虚拟函数调用的实际函数最终取决于调用它的对象的实际类型

[class.virtual]下标准中的一些(非规范性)注释说明了大致相同的内容:

[注3:虚拟函数调用的解释取决于调用对象的类型(动态类型)

[注4:[…]虚拟函数调用依赖于特定对象来确定要调用的函数


如果您想知道虚拟功能分派是如何进行的,您需要寻找一个具体的实现,因为虚拟功能分派的方式没有标准化

(我非常喜欢这篇文章——虚拟表的基本概览,它展示了使用C实现虚拟表的一种可能方法)

发表评论