标准C++无运行时反射,插件式反射靠显式导出C函数、稳定ABI及手动类型映射实现;dlsym/GetProcAddress失败主因是name mangling或导出配置错误,须用extern "C"、__declspec(dllexport)、-fPIC/-shared等确保符号可见。

标准 C++ 没有运行时反射能力,所谓“插件式反射架构”不是靠 std::reflexpr 或 reflect 关键字自动发现类型,而是靠显式导出的 C 风格函数 + 稳定 ABI 接口 + 手动类型映射来实现。你无法在主程序里直接 dlsym 出一个类实例,更不能指望编译器跨 DLL 边界帮你做虚表绑定或 dynamic_cast。
为什么 dlsym / GetProcAddress 找不到 create_plugin 符号
符号找不到,90% 是 name mangling 或导出配置问题,不是代码逻辑错。
- Linux 下没加
extern "C"—— C++ 编译器会对函数名做修饰,dlsym查的是原始符号名,比如_Z13create_pluginv,而不是你写的create_plugin - Windows 下没加
__declspec(dllexport),或者导出方式用了 .def 文件但拼写不一致(大小写敏感) - 编译插件时没加
-fPIC -shared(Linux)或没用/LD(MSVC),导致符号表未生成或不可见 - 用
DumpBin /exports plugin.dll(Windows)或nm -D libplugin.so(Linux)确认导出列表,比盲猜快十倍
如何定义跨 DLL 边界安全的接口
别把 C++ 类当接口用。虚函数表、RTTI、STL 容器、异常机制,在 DLL 边界都不可靠。
- 接口必须是纯 C 风格:用
struct包裹函数指针,例如struct PluginAPI { void* (*create)(); void (*destroy)(void*); int (*process)(void*, const char*); }; - 禁止在接口中出现
std::string、std::vector、引用、模板特化、非 trivial 析构函数 - 字符串统一用
const char*,内存所有权必须明确约定:谁分配、谁释放,并在文档里写死 - 类型识别不用
typeid或dynamic_cast,改用插件导出的const char* plugin_type_name()做字符串比对
LoadLibrary / dlopen 失败却不报具体原因
不查错误码,等于没做错误处理。Windows 和 Linux 的失败路径完全不同,但都藏在系统 API 返回值里。
- Windows 下
LoadLibrary返回NULL后,**必须立刻调GetLastError()**;常见错误码:ERROR_MOD_NOT_FOUND(路径不对)、ERROR_PROC_NOT_FOUND(符号名错或没extern "C")、ERROR_DLL_NOT_FOUND(依赖的运行时 DLL 缺失) - Linux 下
dlopen失败后,调dlerror(),返回值是可读字符串,比如 “undefined symbol: create_plugin” 就说明导出没生效 - 路径必须是绝对路径:Windows 用
GetFullPathName,Linux 用realpath,别信相对路径在所有场景下都有效 - 依赖 DLL 要么放系统目录,要么调
SetDllDirectory(L".")(Windows)或设置LD_LIBRARY_PATH(Linux),否则加载会静默失败
插件热重载后行为异常的根本原因
不是接口设计问题,是全局状态没清理干净。DLL 卸载不会自动析构静态变量或第三方 SDK 实例。
- 插件内禁用
static std::map、static spdlog::logger*这类全局对象;改用插件实例的成员变量 - 所有第三方初始化(如
FMOD::System::create()、glfwInit())必须在shutdown()函数里显式释放,不能依赖 DLL 卸载 -
HMODULE或void*句柄不能长期缓存——FreeLibrary或dlclose后再用会静默崩溃,因为句柄已失效但 API 不报错 - 热重载前,主程序必须确保所有插件对象已销毁、所有回调已注销、所有线程已退出,否则新插件初始化可能撞上旧状态
最常被忽略的一点:插件和主程序必须使用完全一致的构建配置——相同的编译器版本、相同的 STL 实现(/MD vs /MT)、相同的 ABI 设置(_GLIBCXX_USE_CXX11_ABI)。差一个选项,sizeof(IPlugin) 就可能不同,虚表偏移就错位,崩溃发生时连堆栈都不可信。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











