You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

成员函数指针的工作原理是什么?含普通与虚成员函数场景分析

成员函数指针到底存的啥?

你说的完全对——普通函数指针就是直接存目标函数的起始内存地址,调用的时候跳过去就行,简单直接。但成员函数指针的情况可就复杂多了,毕竟它得同时搞定普通成员函数和虚函数两种完全不同的调用逻辑,具体存啥得看它指向的是哪种函数:

1. 指向普通非虚成员函数的指针

其实编译器处理普通非虚成员函数时,暗地里把它改成了带隐式this指针作为第一个参数的普通函数。那对应的成员函数指针里存的东西,就是这个“被改造后的普通函数”的起始地址,再加上一点点额外信息:这个函数属于哪个类(用来做类型安全检查,比如防止你把Derived类的成员函数指针乱赋值给Base类的指针,除非是合法的继承关系)。

说白了,它存的就是俩核心内容:

  • 目标函数的实际内存地址
  • 所属类的类型标识(用来确保类型合法)

2. 指向虚函数的成员函数指针

虚函数就不一样了,因为虚函数的实际调用地址是运行时通过对象的虚表(vtable)找的,编译期根本不知道具体要调用哪个(比如子类重写了的话,调用的就是子类的版本)。所以这种成员函数指针存的不是直接的函数地址,而是虚表中的偏移量——意思就是:调用的时候,先找到当前对象的vptr(虚表指针),然后根据这个偏移量去vtable里找对应的函数地址,再结合this指针执行。

不少编译器还会在成员函数指针里加个标记位,用来区分它是指向普通成员函数还是虚函数,这样调用的时候就能走不同的逻辑:

  • 如果是普通成员函数:直接用存的地址+this指针调用就行
  • 如果是虚函数:先取对象的vptr找vtable,用偏移量定位函数地址,再调用

给你整个直观的例子

假设我们有这么个类结构:

class Base {
public:
    void non_virtual_func() {}
    virtual void virtual_func() {}
};

class Derived : public Base {
public:
    void virtual_func() override {}
};
  • 当你拿&Base::non_virtual_func的时候,这个指针里存的就是non_virtual_func的实际地址,再加上Base类的类型信息
  • 当你拿&Base::virtual_func的时候,这个指针里存的是Base类vtable中virtual_func的偏移量,还有个标记说这是虚函数调用

调用逻辑也不一样:

  • 非虚成员函数指针:obj.*func_ptr() 其实就相当于调用 non_virtual_func(&obj)
  • 虚成员函数指针:obj.*func_ptr() 是先取obj的vptr,按偏移量找函数地址,再调用func_addr(&obj)

内容的提问来源于stack exchange,提问作者doron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:02:28