如何用sol2将C++抽象类接口暴露给Lua并实现调用?
在sol2中实现C++抽象类与Lua继承调用的方案
要在sol2中实现C抽象类接口并让Lua继承实现,核心思路是通过桥接类把Lua对象包装成符合C抽象类要求的实例——因为sol2无法直接绑定纯虚函数供Lua重写。以下是完整实现步骤:
1. C++端核心实现
定义抽象类loopable
class loopable { public: virtual ~loopable() = default; virtual void loop() = 0; // 纯虚函数,定义接口规范 };
实现Lua桥接类
这个类继承自loopable,负责把C++的loop()调用转发到Lua对象的实现上:
#include <sol/sol.hpp> #include <memory> #include <vector> class loopable_lua_bridge : public loopable { private: sol::object m_lua_obj; public: explicit loopable_lua_bridge(sol::object lua_obj) : m_lua_obj(std::move(lua_obj)) {} void loop() override { // 获取Lua对象的loop方法并调用,传入self参数以符合Lua面向对象语法 sol::function loop_func = m_lua_obj["loop"]; loop_func(m_lua_obj); } };
修改engine类支持Lua对象
让engine的add_loopable支持两种重载:一种接收C++原生的loopable智能指针,另一种接收Lua对象并自动包装成桥接实例:
class engine { private: std::vector<std::unique_ptr<loopable>> m_loopables; public: // 接收C++实现的loopable实例 void add_loopable(std::unique_ptr<loopable> obj) { m_loopables.push_back(std::move(obj)); } // 接收Lua对象,自动创建桥接实例 void add_loopable(sol::object lua_obj) { m_loopables.push_back(std::make_unique<loopable_lua_bridge>(std::move(lua_obj))); } void run() { for (auto& obj : m_loopables) { obj->loop(); // 统一调用接口,无需区分是C++还是Lua实现 } } };
2. sol2绑定代码
不需要把loopable绑定为usertype,只需暴露一个空表给Lua作为继承的"标记",保持Lua代码的原有写法:
int main() { sol::state lua; lua.open_libraries(sol::lib::base); // 暴露loopable空表,供Lua继承 lua["loopable"] = sol::table(); // 绑定engine类,需明确指定add_loopable的重载版本 lua.new_usertype<engine>("engine", sol::constructors<engine()>(), "add_loopable", sol::overload( static_cast<void(engine::*)(std::unique_ptr<loopable>)>(&engine::add_loopable), static_cast<void(engine::*)(sol::object)>(&engine::add_loopable) ), "run", &engine::run ); // 加载并执行Lua代码 lua.script(R"( local Actor = setmetatable({}, {__index = loopable}) function Actor:new() local obj = {} setmetatable(obj, self) self.__index = self return obj end function Actor:loop() print("Actor:loop") end local a = Actor:new() local e = engine:new() e:add_loopable(a) e:run() )"); return 0; }
关键说明
- sol2不支持直接绑定纯虚函数让Lua重写,因为C纯虚函数要求必须有具体实现,桥接类相当于做了一层适配,把Lua的方法调用转成C能识别的接口。
- 暴露空的
loopable表给Lua,是为了让Lua代码保持原来的继承写法,无需修改业务逻辑。 add_loopable的重载设计让engine同时兼容C++原生实现和Lua实现的loopable实例。
内容的提问来源于stack exchange,提问作者Rodrigo
相关产品推荐
相关产品推荐

