我试图执行以下代码
\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实现虚拟表的一种可能方法)