我目前能够将C ++类绑定到Lua,包含在我使用luaL_requiref
加载的模块中,并使用适当的静态打开函数执行luaL_newmetatable
,luaL_setfuncs
等处理。效果很好。
但是如果我想绑定一个嵌套类呢?
考虑以下C ++代码:
class Foo {
public:
Foo(){}
void do_something();
class Bar {
public:
Bar(){}
void do_something_else();
};
};
和Lua注册:
int foo_new(lua_State* L) {
new(lua_newuserdata(L, sizeof(foo)))foo();
luaL_setmetatable(L, "Foo");
return 1;
}
int foo_do_something(lua_State* L) {
Foo* foo = (Foo*)luaL_checkudata(L, 1, "Foo");
foo->do_something();
return 0;
}
int luaopen_foo(lua_State* L) {
const luaL_Reg functions[] = {
{"__index", foo_new},
{"do_something", foo_do_something},
{nullptr, nullptr}
};
if( luaL_newmetatable(L, "Foo") ) {
luaL_setfuncs(L, functions, 0);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
}
return 1;
}
...
luaL_requiref(L, "Foo", luaopen_foo, 1);
我可以在Lua中访问Foo::do_something()
:
foo = Foo()
foo:do_something()
现在问题:如何在Lua中注册Foo::Bar
嵌套类,以便我可以这样访问它:
bar = Foo.Bar()
bar:do_something_else()
基本上,我想在Bar
metatable而不是全局注册Foo
方法。我是否需要再次拨打luaL_requiref
,或者我可以在一个luaL_requiref
中进行此操作吗?
谢谢!
答案 0 :(得分:0)
是的,您可以通过一次通话完成。
luaL_requiref
函数只是调用带有铃声和口哨声的传递函数,例如检查模块是否尚未加载(并更新package.loaded
表),注册相应的全局值等等。
我认为您不希望在Bar
或Foo
与[{1}}分开加载Foo
,因此只需Bar
个条目"Foo"
应该足够了。同样,全局package.loaded
变量也不需要。
所以,只需将其作为Bar
的一个字段,即可。
P.S。确保您的析构函数被调用:通常,如果您将Foo
与展示位置新用,则需要使用lua_newuserdata
元方法。
EDIT2:修改你的luaopen_Foo方法(注意__gc
,而不是__call
为构造函数。我个人更喜欢__index
用于此目的,但如果你想创建它们{{1那么你需要new
):
local f = Foo()
如果你好奇,luaL_requiref函数(带有一些伪代码)是什么:
__call
请注意区别:int luaopen_foo(lua_State* L)
{
static const luaL_Reg functions[] =
{
{"__call" , foo_new},
{"do_something" , foo_do_something},
{nullptr , nullptr}
};
if (luaL_newmetatable(L, "Foo"))
{
luaL_setfuncs(L, functions, 0);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
// =================
// Here, your "Foo" metatable is on top of your stack
// about to be returned as the result of your luaopen_Foo.
// Simply put another table above and set if as a Foo.Bar
if (luaopen_FooBar(L))
lua_setfield(L, -2, "Bar");
}
return 1;
}
int luaopen_FooBar(lua_State * L)
{
static const luaL_Reg functions[] =
{
{"__call" , foo_bar_new},
{"do_something_else" , foo_bar_do_something_else},
{nullptr , nullptr}
};
// luaL_newmetatable puts its result on top of the stack
// - exactly what we want for lua_setfield
if (luaL_newmetatable(L, "Foo::Bar"))
{
luaL_setfuncs(L, functions, 0);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
}
return 1; // Indicate the result is on top of the stack
}
从Lua中调用您的函数,这可确保在执行后正确清理堆栈,例如:你可以在那里放一些垃圾,你必须要确保你的顶级值是你想要与void luaL_requiref(lua_State *L, const char *name, lua_CFunction openf, int set_global)
{
if (!try_get_already_loaded_module(modname))
{
lua_pushcfunction(L, openf); // Call the openf function
lua_pushstring(L, modname); // with modname as its argument
lua_call(L, 1, 1);
memorize_the_result_for_future(modname);
}
if (set_global)
{
lua_pushvalue(L, -1); // copy the module
lua_setglobal(L, modname); // set _G[modname] = module
}
}
一起产生的。但是,如果直接调用该函数,那么你就不会有这种奢侈。因此,请确保仅在堆栈顶部添加单个值。