C++ 通过「对象指针」调用「类成员函数指针」

一次性讲透:->* 是什么语法、c_.get()->*m 整行怎么执行

先给结论:
->* 是 C++ 专属语法:通过「对象指针」调用「类成员函数指针」

一、先分清三种基础语法

  1. . :对象 访问成员
  2. -> :对象指针 访问成员
  3. ->*:对象指针 调用成员函数指针 / 成员变量指针

二、先搞懂:普通成员函数 vs 普通函数指针 vs 成员函数指针

1. 普通正常调用

class Proxy {
public:
    void test(int a) {}
};

Proxy obj;
obj.test(10);        // 对象.普通函数

Proxy* p = &obj;
p->test(10);         // 对象指针->普通函数

2. 普通函数指针

using NormalFuncPtr = void (*)(int);
void normalFunction(int a) {}
NormalFuncPtr ptr = &normalFunction;

3. 成员函数指针(你代码里的 m

// 定义一个类型:Proxy 的成员函数指针
// void - 函数的返回类型
// (Proxy::*) - 表示这是一个指向 Proxy 类成员函数的指针
// (int) - 函数的参数类型
// FuncPtr 是一个类型别名,表示指向 Proxy 类中接受 int 参数并返回 void 的成员函数的指针。
using FuncPtr = void (Proxy::*)(int);

// 取函数地址
FuncPtr m = &Proxy::test;

现在 m 存的是 test 这个函数的地址
不能直接 m(10) 调用,因为它属于类,必须绑定一个对象/对象指针。

3.1. 为什么要用成员函数指针?

  • 多态行为:可以在运行时决定调用哪个成员函数
  • 回调机制:用于实现回调函数模式
  • 设计模式:在策略模式、命令模式等中很有用
    实际应用场景
  class Button {
  public:
    using ClickHandler = void (Button::*)(int);
    
    void setClickHandler(ClickHandler handler) {
        clickHandler_ = handler;
    }
    
    void click(int clicks) {
        if (clickHandler_) {
            (this->*clickHandler_)(clicks);
        }
    }
    
  private:
    ClickHandler clickHandler_ = nullptr;
  };

  class MyApp {
  public:
      void handleSingleClick(int) {
        std::cout << "Single click handled" << std::endl;
    }
    
      void handleDoubleClick(int) {
        std::cout << "Double click handled" << std::endl;
    }
  };

  int main() {
      MyApp app;
      Button button;
    
      // 设置不同的点击处理器
      button.setClickHandler(&MyApp::handleSingleClick);
      button.click(1);
    
      button.setClickHandler(&MyApp::handleDoubleClick);
      button.click(2);
    
      return 0;
}
using ClickHandler = void (Button::*)(int);定义了一个指向 Button 类成员函数的指针类型,用于实现运行时多态的函数调用。

三、->* 登场:绑定对象指针 + 成员函数指针

语法固定格式:

(对象指针 ->* 成员函数指针)(参数...);

示例:

Proxy* p = &obj;
FuncPtr m = &Proxy::test;

// 固定写法
(p ->* m)(10);
  • p:类对象的裸指针
  • m:成员函数指针
  • ->*:连接两者、发起调用
  • 外面必须包一层小括号,再跟参数列表 (...)

四、套进源码里的代码

// c_ 是 std::shared_ptr<C>
(c_.get()->*m)(std::get<Is>(args)...);

逐层拆解:

  1. c_.get()
    shared_ptr 取出原始裸指针 C*

  2. ->*
    固定语法:用左边的裸指针,调用右边的成员函数指针

  3. m
    就是我用 static_cast 强转出来的:
    CarConfigurationManagerServiceProxy::InstallCarconfigAsync
    异步版本的成员函数指针

  4. std::get<Is>(args)...
    把打包在 tuple 里的参数逐个解包,传给函数


五、为什么不能直接用 shared_ptr 写?

// 错误写法
(c_ ->* m)(...);

C++ 不支持智能指针直接参与 ->* 运算,
只能用原生裸指针,所以必须 c_.get() 先取裸指针。


六、再简化成大白话

(c_.get()->*m)(args...);

翻译:

拿出智能指针里的原始对象地址,
用这个对象地址,调用存放在 m 里的那个成员函数,
把解包后的参数传进去。


七、配套记忆口诀

  • 普通函数:对象用 . ,指针用 ->
  • 成员函数指针:指针必须用 ->*
  • 格式死记:(对象指针->*函数指针)(参数)
  • shared_ptr 要先 .get() 拿裸指针才能用 ->*

posted on 2026-05-11 14:49  四季萌芽V  阅读(2)  评论(0)    收藏  举报

导航