调用DLL中虚成员时类静态字段被清零的技术问题
问题核心原因
你遇到的是跨EXE与DLL模块的静态成员变量副本冲突问题:
因为IRFile是仅头文件实现的类,EXE和DLL在编译时会各自生成该类的静态成员_callback实例。DLL里的GGen::generate初始化的是DLL模块内的_callback,但EXE中调用虚函数buildFile时,访问的是EXE自身模块里的那份_callback,自然会出现断言失败。
可行解决方案
方案1:统一静态成员的定义位置
将IRFile的静态成员在头文件中仅声明,然后在**固定一个模块(比如EXE或DLL)**中定义,确保整个程序只有一份实例:
// IRFile.h class IRFile { public: static void(*_callback)(void); // 仅声明静态成员 virtual void buildFile() { assert(_callback != nullptr); // 业务逻辑 } }; // 在EXE的某.cpp文件中定义(选EXE或DLL其一即可) void(*IRFile::_callback)(void) = nullptr;
这样EXE和DLL访问的都是同一个静态成员实例,不会出现多副本问题。
方案2:用单例封装回调
把回调封装到全局单例对象中,强制整个程序只有一份回调实例:
// CallbackHolder.h class CallbackHolder { private: CallbackHolder() = default; void(*_callback)(void) = nullptr; public: static CallbackHolder& getInstance() { static CallbackHolder instance; return instance; } void setCallback(void(*cb)(void)) { _callback = cb; } void(*getCallback())(void) { return _callback; } }; // IRFile.h class IRFile { public: virtual void buildFile() { auto cb = CallbackHolder::getInstance().getCallback(); assert(cb != nullptr); cb(); // 使用回调 } };
在GGen::generate中调用CallbackHolder::getInstance().setCallback(cbFile)即可,模块间访问的是同一个单例内的回调。
方案3:将IRFile改为DLL导出类
把IRFile的实现移到DLL中并导出,让EXE导入使用同一个类实例:
// IRFile.h #ifdef BUILD_DLL #define IR_API __declspec(dllexport) #else #define IR_API __declspec(dllimport) #endif class IR_API IRFile { public: static void(*_callback)(void); virtual void buildFile(); }; // IRFile.cpp(DLL项目中) #include "IRFile.h" void(*IRFile::_callback)(void) = nullptr; void IRFile::buildFile() { assert(_callback != nullptr); // 业务逻辑 }
这种方式下,静态成员和虚函数表都仅在DLL中存在,彻底避免模块间的类实例冲突。
内容的提问来源于stack exchange,提问作者kilian3008
相关产品推荐
相关产品推荐

