C++ 通过「对象指针」调用「类成员函数指针」
一次性讲透:->* 是什么语法、c_.get()->*m 整行怎么执行
先给结论:
->* 是 C++ 专属语法:通过「对象指针」调用「类成员函数指针」
一、先分清三种基础语法
.:对象 访问成员->:对象指针 访问成员->*:对象指针 调用成员函数指针 / 成员变量指针
二、先搞懂:普通成员函数 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)...);
逐层拆解:
-
c_.get()
从shared_ptr取出原始裸指针C* -
->*
固定语法:用左边的裸指针,调用右边的成员函数指针 -
m
就是我用static_cast强转出来的:
CarConfigurationManagerServiceProxy::InstallCarconfigAsync
异步版本的成员函数指针 -
std::get<Is>(args)...
把打包在 tuple 里的参数逐个解包,传给函数
五、为什么不能直接用 shared_ptr 写?
// 错误写法
(c_ ->* m)(...);
C++ 不支持智能指针直接参与 ->* 运算,
只能用原生裸指针,所以必须 c_.get() 先取裸指针。
六、再简化成大白话
(c_.get()->*m)(args...);
翻译:
拿出智能指针里的原始对象地址,
用这个对象地址,调用存放在 m 里的那个成员函数,
把解包后的参数传进去。
七、配套记忆口诀
- 普通函数:对象用
.,指针用-> - 成员函数指针:指针必须用
->* - 格式死记:
(对象指针->*函数指针)(参数) - shared_ptr 要先
.get()拿裸指针才能用->*
浙公网安备 33010602011771号