C/C++中实现__index元方法
2018-6-15 18:42:40
收藏:0
阅读:78
评论:2
我有一个 C++ 回调/函数对象系统的脚本,可以使用字符串和/或变量调用任何“已注册”的 C++ 函数。
//已删除此帖子的错误检查和错误代码
int LuaGameObject::LuaCallFunction( lua_State *luaState )
{
if ( lua_isuserdata( luaState, 1 ) == 1 )
{
int nArgs = lua_gettop( luaState );
//获取 GameObject
OGameObject* pGameObject = static_cast<OGameObject*>(lua_touserdata( luaState, 1 ));
if ( pGameObject )
{
//获取 FunctionName
const char* functionNameString = lua_tostring( luaState, 2 );
//获取 Arguments
std::vector<OVariant> args;
for ( int i = 3; i <= nArgs; ++i )
{
OVariant variant;
variant.SetFromLua( luaState, i );
args.push_back( variant );
}
//调用它!
CallGameObjectFunction( luaState, pGameObject, functionNameString, args );
return 1;
}
}
return 0;
}
OVariant LuaGameObject::ExecuteLua()
{
lua_State *lState = luaL_newstate();
luaL_openlibs( lState );
lua_register( lState, "Call", LuaCallFunction );
luaL_loadstring( lState, m_pScript );
//现在运行它
lua_pcall( lState, 0, 1, 0 );
//处理返回值
OVariant result;
result.SetFromLua( lState, -1 );
lua_close( lState );
return result;
}
在 Lua 中,我可以这样做...
local king = Call("EmpireManager","GetKing")
Call("MapCamera","ZoomToActor",king)
然而,我感觉可以使用 __index 元方法来简化 Lua...
local king = EmpireManager:GetKing()
MapCamera:ZoomToActor(king)
我希望通过使用以下 __index 元方法实现简化的 Lua
这是我如何注册 __index metafunction 的方式...(大部分从在线示例中复制)
void LuaGameObject::Register( lua_State * l )
{
luaL_Reg sRegs[] =
{
{ "__index", &LuaGameObject::LuaCallFunction },
{ NULL, NULL }
};
luaL_newmetatable( l, "luaL_EmpireManager" );
// 把 C 函数注册到我们刚刚创建的 metatable 中
luaL_setfuncs( l, sRegs, 0 );
lua_pushvalue( l, -1 );
// 使 metatable 的 "__index" 字段指向自身
// 这将弹出堆栈
lua_setfield( l, -1, "__index" );
// 现在使用 setglobal 正式向 Lua 公开 luaL_EmpireManager metatable
// 并使用名称“EmpireManager”
lua_setglobal( l, "EmpireManager" );
}
不幸的是,我似乎无法正确设置回调。Lua 正确调用我的 LuaGameObject::LuaCallFunction,但堆栈不包含我想要的内容。在 LuaGameObject::LuaCallFunction 中,我可以找到函数名称和 EmpireManager 对象的堆栈。但是,我找不到堆栈中的参数。设置方式是什么?还是不可能的?
点赞
用户9822560
在 Lua 中,可以给“userdata”类型添加方法,如官方网站上Programming in Lua所述。
当你输入以下 Lua 代码时:
myUserdata:someMethod(arg1,arg2,arg3)
假设myUserdata是一个“userdata”对象,则解析器将执行以下操作。
- 调用
getmetatable(myUserdata).__index(myUserdata,"someMethod")来获取someMethod的值。 - 调用
someMethod(myUserdata,arg1,arg2,arg3),而someMethod可以是任何在 Lua 中可调用的函数,例如:Lua 函数、C 函数或具有__call元方法的表/用户数据。
你的__index元方法应该只返回一个实现该方法的函数(或另一个在 Lua 中可调用的对象)。像这样:
// 不太准确的 __index 元方法名称(有一个 __call 元方法)
int LuaGameObject::LuaCallFunction( lua_State *l)
{
// 待完成:错误检查
OGameObject* pGameObject = static_cast<OGameObject*>(lua_touserdata( luaState, 1 ));
std::string memberName = lua_tostring( luaState, 2 );
int result = 1;
if (memberName == "method1") {
lua_pushcfunction(l,LuaGameObject::luaMethod1);
} else if (memberName == "method2") {
lua_pushcfunction(l,LuaGameObject::luaMethod2);
} else {
result = 0;
}
return result;
}
返回的__index元方法函数的基本骨架:
int LuaGameObject::luaMethod1(lua_State* l) {
// todo:错误检查。
OGameObject* pGameObject = static_cast<OGameObject*>(lua_touserdata(l, 1));
float arg1 = lua_tonumber(l, 2);
// 获取其他参数
pGameObject->method1(arg1 /*, 如果有其他参数则为这里补充*/);
// 可选:将返回值压入堆栈。
return 0; // <-- 返回值的数量。
}
2018-06-16 13:55:02
评论区的留言会收到邮件通知哦~
推荐文章
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的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 代码?

好的,经过更多的研究,我现在相信我不能使用 __index 元函数来调用带参数的 c 函数。它只传递表名和键到回调函数。
然而,对于任何有兴趣的人来说,它可以用于类似于表的对象,但不适用于函数(因为参数不会压入堆栈)。我将它用于我的 "property" 对象。它们没有参数,可以在 lua 中如下使用...
local king = EmpireManager:king king:name = "Arthur" local name = king:name这些适当地链接和调用相应的 C++ 对象函数
Actor::SetName(std::string name) std::string Actor::GetName()