如何使用Sol2实现Lua可访问的C++类指定方法的不可修改性
如何使用Sol2实现Lua可访问的C++类指定方法的不可修改性
嘿,我完全理解你的需求——想让导出到Lua的C++类里,特定方法不能被Lua代码覆盖,同时允许其他方法可以自由修改。结合Sol2的特性,这里有个精准的解决方案,刚好匹配你的场景:
首先要明确一个关键点:你的Lua代码里是在修改代表C++类的Lua table(也就是object这个全局表)里的方法,而不是实例的方法。所以我们需要给这个类table设置一个拦截逻辑,阻止对特定键的修改。
具体实现步骤
- 修正C++代码的小问题:你原来用了
mutable作为函数名,这是C++的关键字,会导致编译错误,我先把它改成mutable_func,后续代码都用这个名字。 - 给类table添加元表拦截:利用Lua的元表机制,给
object类table设置__newindex元方法,当尝试修改指定键时抛出错误。
修改后的完整代码
#define SOL_ALL_SAFETIES_ON 1 #include "lua/sol.hpp" #include <iostream> struct Object { Object() {} void mutable_func() { std::cout << "mutable method called\n"; } void immutable() { std::cout << "immutable method called\n"; } }; int main() { sol::state lua; lua.open_libraries(sol::lib::base); // 创建usertype并绑定方法 auto object = lua.new_usertype<Object>("object", sol::constructors<Object()>()); object["mutable_func"] = &Object::mutable_func; object["immutable"] = &Object::immutable; // 获取Lua中的object类表 sol::table object_table = lua["object"]; // 创建元表,定义修改拦截逻辑 sol::table mt = lua.create_table(); mt[sol::meta_function::new_index] = [](sol::table self, sol::stack_object key, sol::stack_object value) { // 将键转换为字符串,判断是否是我们要保护的方法 sol::optional<std::string> key_name = key.as<std::optional<std::string>>(); if (key_name && *key_name == "immutable") { // 抛出Sol2错误,会被Lua的safe_script捕获 throw sol::error("can't change immutable method"); } // 允许修改其他所有键 self.rawset(key, value); }; // 给类表绑定元表 object_table.set_metatable(mt); sol::string_view code = R"( -- 这一行会触发错误:'can't change immutable method' function object:immutable() print("Changed") end -- 这一行可以正常修改方法 function object:mutable_func() print("Also changed") end obj = object.new() obj:immutable(); obj:mutable_func(); )"; sol::protected_function_result result = lua.safe_script(code, &sol::script_pass_on_error); if (!result.valid()) { sol::error error = result; std::cout << error.what() << '\n'; } }
代码解释
- 当Lua尝试给
object表的某个键赋值时,__newindex元方法会被触发。 - 我们检查键名是否是
immutable,如果是则抛出Sol2的错误,这个错误会被safe_script捕获并输出。 - 对于其他键(比如
mutable_func),我们调用rawset直接完成赋值,允许正常修改。
额外说明
如果你还想阻止修改实例对象的方法(比如obj.immutable = function() ... end),可以给Object的usertype也设置__newindex元方法,逻辑和上面类似,只需要把拦截对象换成实例即可。
备注:内容来源于stack exchange,提问作者vitopigno
相关产品推荐
相关产品推荐

