You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Sol2实现Lua可访问的C++类指定方法的不可修改性

如何使用Sol2实现Lua可访问的C++类指定方法的不可修改性

嘿,我完全理解你的需求——想让导出到Lua的C++类里,特定方法不能被Lua代码覆盖,同时允许其他方法可以自由修改。结合Sol2的特性,这里有个精准的解决方案,刚好匹配你的场景:

首先要明确一个关键点:你的Lua代码里是在修改代表C++类的Lua table(也就是object这个全局表)里的方法,而不是实例的方法。所以我们需要给这个类table设置一个拦截逻辑,阻止对特定键的修改。

具体实现步骤

  1. 修正C++代码的小问题:你原来用了mutable作为函数名,这是C++的关键字,会导致编译错误,我先把它改成mutable_func,后续代码都用这个名字。
  2. 给类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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 12:44:39