【发布时间】:2021-10-31 07:40:56
【问题描述】:
我执行了以下代码。
#include <iostream>
class Base
{
public:
virtual void func()
{
std::cout<<"Base func called"<<std::endl;
}
};
class Derived: public Base
{
public:
virtual void func() override
{
std::cout<<"Derived func 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 func called。然而,相反,输出是
Derived func called
这让我很惊讶,因为我认为func_ptr 应该只能看到Base 成员(因为我认为func_ptr 不是通过_vptr 访问成员函数,而是函数地址本身。
我想知道,在这种情况下,虚拟调度是如何发生的(对虚拟表的访问是如何发生的),以及这种行为在 C++ 标准中的定义位置(我不能找到什么)?
【问题讨论】:
-
我相信这是作为“偏移量”实现的,因此它会从
this指针加上偏移量指向它所指向的任何类型。因为它指向一个实际的 Derived 对象,所以它是正在运行的函数。 -
如果你想一想,当你写
bptr->func时,编译器也将func解析为Base::func,只有在运行时它才会被解析为正确的调用。 -
标准中没有提到虚拟表。它们是特定编译器的实现细节。 VTable 并不是实现虚拟方法的唯一方式,它只是最常见的方式。
-
指向成员函数的指针与指针不同。当它指向的成员函数是一个虚函数时,它有足够的数据来处理虚调度。
标签: c++ function-pointers virtual-functions member-pointers