虚函数表是实现多态特性重要的数据结构。在类中用vptr成员指针保存虚函数表的内存地址。虚函数表保存虚函数的地址,用于动态查找对象真实类型关联的方法。vptr一般保存于对象内存布局的头几个字节(指针大小)。下面是获取虚函数表中虚函数的例子:
class base {
public:
virtual void show() { std::cout << "show_base" << std::endl; }
virtual void on_base() { std::cout << "on_base" << std::endl; }
};
class derive : public base {
public:
void show() { std::cout << "show_derive" << std::endl; };
};
// 获取vptr的值
static void *_get_addr(void *obj, size_t offset) {
size_t ptrsize = sizeof(void *);
return *(void**)((char *)obj + offset * ptrsize);
}
using func_t = void (*)();
// 获取vtable中,成员(虚函数指针)的值
static func_t _get_func_addr(void *vptr, size_t offset) {
size_t ptrsize = sizeof(void *);
return (func_t)(*(void**)((char *)vptr + offset * ptrsize));
}
int main(void) {
derive der;
base *d = &der;
void *vptr = _get_addr(d, 0); // 获取对象中vptr的值
std::cout << "vptr: " << vptr << std::endl;
func_t der_show_addr = _get_func_addr(vptr, 0);
der_show_addr();
func_t der_on_base_addr = _get_func_addr(vptr, 1);
der_on_base_addr();
}
输出:
vptr: 0x561943555d78
show_derive
on_base
从上面的例子可以得出:
vptr成员保存在对象头几个字节(指针大小)。派生类实现的虚函数在虚函数表中会覆盖基类的虚函数,没有实现的虚函数则继承自基类。