从 C 导出类时 Lua 的方法和属性
2015-1-13 14:0:51
收藏:0
阅读:83
评论:1
我使用lua作为我的3D引擎的脚本语言。我有几个对象的lua“类”,现在我想使用属性而不是getter和setter。因此,而不是像这样:
local oldState = ui:GetChild("Panel1"):GetVisible()
ui:GetChild("Panel1"):SetVisible(not oldState)
我会这样做:
ui.Panel1.visible = not ui.Panel1.visible
问题是我的C++代码用于创建metatable和覆盖__index方法。这里是它,顺便说一下:
1.创建metatable:
void CLUAScript::RegisterClass(const luaL_Reg funcs[], std::string const& className)
{
luaL_newmetatable(m_lua_state, std::string("Classes." + className).c_str());
luaL_newlib( m_lua_state, funcs);
lua_setglobal(m_lua_state, className.c_str());
}
2.实例化类(lua对象仅保存指向存储在C++代码中的实际数据的指针):
int CLUAScript::NewInstanceClass(void* instance, std::string const& className)
{
if (!instance)
{
lua_pushnil(m_lua_state);
return 1;
}
luaL_checktype(m_lua_state, 1, LUA_TTABLE);
lua_newtable(m_lua_state);
lua_pushvalue(m_lua_state,1);
lua_setmetatable(m_lua_state, -2);
lua_pushvalue(m_lua_state,1);
lua_setfield(m_lua_state, 1, "__index");
void **s = (void **)lua_newuserdata(m_lua_state, sizeof(void *));
*s = instance;
luaL_getmetatable(m_lua_state, std::string("Classes." + className).c_str());
lua_setmetatable(m_lua_state, -2);
lua_setfield(m_lua_state, -2, "__self");
return 1;
}
问题是如何同时具有方法和属性。如果我只将__index添加到CLUAScript::RegisterClass函数数组中,它将永远不会被调用。我无法想象在CLUAScript::NewInstanceClass中删除其重新定义的方法。
点赞
评论区的留言会收到邮件通知哦~
推荐文章
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
问题在于如何同时拥有方法和属性。
广义来讲,方法只是恰好转化为函数的属性。
如果我只是将 __index 添加到 RegisterClass 函数数组中,它就永远不会被调用。
这才是实际问题,对于你的问题来说,文章其余部分只是分散注意力。
根据文档,luaL_newlib 会创建一个新表。luaL_newmetatable 也是如此。在 RegisterClass 中你创建了两个表,这是没有意义的。你需要仅创建元表,而且就是这个元表需要添加 __index 和 __newindex 元方法。
如果你希望手动转换数据来回到你的 C++ 类实例属性,你不会让 __index 只是指向一个函数表(实现类方法的快捷方式)。访问时你必须写出一个函数来区分方法(值来自类范围)和属性(值来自实例范围)。
以下是如何在 Lua 中访问方法/属性的例子。虽然使用了 C API,但方法是相同的:
-- 这是你在 RegisterClass 中为 C++ 类 'Foo' 创建的元表 Foo = { } -- 下面是你的 __index 元方法在 C++ 代码中的具体实现,但你需写出代码来区分 'key' 对应 C++ 对象中的哪些属性,然后将其推到栈上。 function Foo.__index(instance,key) local method = rawget(Foo,key) if method then return method end return instance.properties[key] end -- 下面是赋值元方法的实现,不过如果你希望用户能够向 Lua 对象中添加属性以兼容 C++ 对象属性,则还需要在正确的位置写入值。 function Foo.__newindex(instance,key,value) instance.properties[key] = value end -- 这不必是元表上的方法 function Foo:new(state) return setmetatable({ properties = state}, self) end -- 一个类方法的例子 function Foo:dump() print('dump:', self.x, self.y) end -- 模拟用户数据,一个 C++ 类实例 cppClassInstance = { x = 10, y = 20, } obj = Foo:new(cppClassInstance) print(obj.x) -- 读取 `x`,它被解析为 cppClassInstance.x obj.x = 5150 -- 写入 'x',写入 cppClassInstance.x print(obj.x) -- 验证更改 obj:dump() -- 调用一个类方法