C++成员函数指针调用报错:无法调用存储对象的存储成员函数
事件系统成员函数指针调用问题解决
问题重现
尝试实现一个事件系统,让event_triggerer存储event_receiver的成员函数指针并调用,但代码出现编译错误:
原代码:
typedef void(event_receiver::* ev_rec_func)(const event_receiver::Msg&); class event_receiver { public: struct Msg { int irrelevant_test_data; }; virtual void event_callback0(const Msg& m) {}; }; class event_triggerer { private: std::vector<std::pair<event_receiver*, ev_rec_func>> suscribers_vec; public: void trigger_event(const event_receiver::Msg& m) { for (std::pair<event_receiver*, ev_rec_func>& e : suscribers_vec) { // 错误:expression must have pointer to member type e.first->*(e.second(m)); } } };
遇到的错误:
原调用语句报错:
expression must have pointer to member type
修改为(e.first->*e.second)(m);后报错:a pointer to a bound function may only be used to call the function
VS中hoverev_rec_func时显示:typedef void ev_rec_func(const &),类型显示异常
错误原因分析
- typedef位置错误:原代码中
typedef写在event_receiver类定义之前,此时编译器还未解析event_receiver类及其内部的Msg结构体,导致ev_rec_func的类型无法被正确解析,这是VS显示异常类型的根本原因,也会引发后续调用错误。 - 成员函数指针调用语法错误:原调用语句
e.first->*(e.second(m))逻辑错误,试图直接调用成员函数指针e.second(成员函数指针必须绑定对象才能调用),然后将结果用于->*操作,完全不符合成员函数指针的调用规则。
修复方案
步骤1:调整typedef位置
将typedef移至event_receiver类定义之后,确保编译器能识别event_receiver和Msg类型:
class event_receiver { public: struct Msg { int irrelevant_test_data; }; virtual void event_callback0(const Msg& m) {}; }; // 现在可以正确解析event_receiver::Msg类型 typedef void(event_receiver::* ev_rec_func)(const event_receiver::Msg&);
步骤2:修正成员函数指针调用语法
正确的成员函数指针调用格式是(对象指针->*成员函数指针)(参数),需要用括号确保优先级:
void trigger_event(const event_receiver::Msg& m) { for (auto& e : suscribers_vec) { // 正确调用方式:先绑定对象和成员函数指针,再传参调用 (e.first->*e.second)(m); } }
完整可编译代码
#include <vector> #include <utility> class event_receiver { public: struct Msg { int irrelevant_test_data; }; virtual void event_callback0(const Msg& m) {}; }; typedef void(event_receiver::* ev_rec_func)(const event_receiver::Msg&); class event_triggerer { private: std::vector<std::pair<event_receiver*, ev_rec_func>> suscribers_vec; public: void trigger_event(const event_receiver::Msg& m) { for (auto& e : suscribers_vec) { (e.first->*e.second)(m); } } // 新增订阅函数用于测试 void subscribe(event_receiver* receiver, ev_rec_func func) { suscribers_vec.emplace_back(receiver, func); } }; // 测试示例 int main() { event_receiver recv; event_triggerer trigger; trigger.subscribe(&recv, &event_receiver::event_callback0); event_receiver::Msg msg{}; trigger.trigger_event(msg); return 0; }
内容的提问来源于stack exchange,提问作者Eric111
相关产品推荐
相关产品推荐

