求将成员函数转为void指针后调用的简单可运行示例(回调需求)
用void指针实现无包装成员函数回调的完整示例
下面是一个可直接编译运行的完整示例,实现通过void指针存储并调用不同类的成员函数,无需额外包装函数或静态成员:
#include <iostream> // 测试类A class ClassA { public: void printMessage(const char* msg) { std::cout << "ClassA: " << msg << std::endl; } }; // 测试类B class ClassB { public: void showNumber(int num) { std::cout << "ClassB: Number is " << num << std::endl; } }; // 回调存储结构:保存对象指针和成员函数指针的void*形式 struct CallbackData { void* objPtr; void* funcPtr; }; // 调用ClassA成员函数的适配器 void invokeClassACallback(CallbackData cb, const char* msg) { // 将void*转回原类型:对象指针+成员函数指针 ClassA* obj = static_cast<ClassA*>(cb.objPtr); void (ClassA::*func)(const char*) = *static_cast<void (ClassA::**)(const char*)>(&cb.funcPtr); // 调用成员函数 (obj->*func)(msg); } // 调用ClassB成员函数的适配器 void invokeClassBCallback(CallbackData cb, int num) { ClassB* obj = static_cast<ClassB*>(cb.objPtr); void (ClassB::*func)(int) = *static_cast<void (ClassB::**)(int)>(&cb.funcPtr); (obj->*func)(num); } int main() { ClassA a; ClassB b; // 准备ClassA的回调数据 CallbackData cbA; cbA.objPtr = &a; // 成员函数指针转void* cbA.funcPtr = reinterpret_cast<void*>(&ClassA::printMessage); // 准备ClassB的回调数据 CallbackData cbB; cbB.objPtr = &b; cbB.funcPtr = reinterpret_cast<void*>(&ClassB::showNumber); // 调用回调 invokeClassACallback(cbA, "Hello from ClassA"); invokeClassBCallback(cbB, 42); return 0; }
关键说明
- 核心逻辑是将对象指针和成员函数指针分别转为
void*存储,调用时再强制转回原类型,必须保证类型完全匹配,否则会触发未定义行为。 - 成员函数指针转
void*需要用reinterpret_cast,因为成员函数指针的大小可能和普通指针不同,这一步在C++标准中属于未定义行为,但主流编译器(GCC、Clang、MSVC)均提供支持。 - 不同签名的成员函数需要对应专属的调用适配器,因为成员函数的签名决定了调用时的参数列表。
注意事项
- 这种方式绕过了C++的类型安全检查,使用时必须严格保证存储和调用的类型一致,否则会导致程序崩溃或不可预期的行为。
- 如果需要更通用、安全的回调机制,推荐使用C++11及以后的
std::function+std::bind组合,或者lambda表达式,它们更易维护且类型安全。
内容的提问来源于stack exchange,提问作者schanti schul
相关产品推荐
相关产品推荐

