如果您想要真正独立的绑定,这里提供了经典的C语言样板代码。只需将“Object”替换为您的类名并实现
// { }
块即可。将
push_Object
从静态变为公共的将为您提供通用的现有对象推入器,该推入器还会在元表中缓存对象(否则,多次推入将创建许多明显存在垃圾回收问题的不同用户数据)。
如果您想要,也可以将其转化为C++或库文件形式,但我个人不这样做,因为如果它是库文件,添加例如__newindex-to-environment代理和其他怪癖将不那么直观。实际上,所有样板都在
push_mt
、
push_Object
、
forget_Object
和
check_Object
中,其他所有内容都需要进行微调。
请注意,这仅绑定了一个单一的类,而不是所有类。
static const char *tname = "Object";
static void push_Object(lua_State *L, Object *object);
static Object *check_Object(lua_State *L, int i);
static int
l_gc(lua_State *L)
{
Object **ud = luaL_checkudata(L, 1, tname);
if (*ud) {
*ud = NULL;
}
return 0;
}
static int
l_tostring(lua_State *L)
{
Object **ud = luaL_checkudata(L, 1, tname);
lua_pushfstring(L, "%s: %p", tname, *ud);
return 1;
}
static int
l_new(lua_State *L)
{
Object *object = NULL;
push_Object(L, object);
return 1;
}
static int
l_method(lua_State *L)
{
Object *object = check_Object(L, 1);
lua_Integer int_arg = luaL_checkinteger(L, 2);
const char *str_arg = luaL_checklstring(L, 3, NULL);
return 0;
}
static const luaL_Reg lib[] = {
{ "new", l_new },
{ "method", l_method },
{ NULL, NULL },
};
static lua_CFunction first_m = l_method;
static void
push_mt(lua_State *L)
{
if (luaL_newmetatable(L, tname)) {
size_t m = 0; while (first_m != lib[m].func) m++;
lua_createtable(L, 0, 0);
luaL_register(L, NULL, &lib[m]);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, l_tostring);
lua_setfield(L, -2, "__tostring");
lua_pushcfunction(L, l_gc);
lua_setfield(L, -2, "__gc");
lua_pushstring(L, tname);
lua_setfield(L, -2, "__metatable");
lua_createtable(L, 0, 0);
lua_createtable(L, 0, 1);
lua_pushstring(L, "v");
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
lua_setfield(L, -2, "objects");
}
}
static void
push_Object(lua_State *L, Object *object)
{
int top = lua_gettop(L);
push_mt(L);
lua_getfield(L, -1, "objects");
lua_pushlightuserdata(L, object);
lua_gettable(L, top+2);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
Object **ud = lua_newuserdata(L, sizeof(*ud));
*ud = object;
lua_pushvalue(L, top+1);
lua_setmetatable(L, -2);
lua_pushlightuserdata(L, object);
lua_pushvalue(L, -3);
lua_pushvalue(L, top+2);
}
lua_replace(L, top+1);
lua_settop(L, top+1);
return;
}
static void
forget_Object(lua_State *L, Object *object)
{
int top = lua_gettop(L);
push_mt(L);
lua_getfield(L, -1, "objects");
lua_pushlightuserdata(L, object);
lua_pushnil(L);
lua_settable(L, top+2);
lua_settop(L, top);
}
static Object *
check_Object(lua_State *L, int i)
{
Object **ud = luaL_checkudata(L, i, tname);
Object *object = *ud;
if (object == NULL)
luaL_error(L, "%s is finalized", tname);
return object;
}
int
luaopen_Object(lua_State *L)
{
push_mt(L);
lua_createtable(L, 0, sizeof(lib)-1);
luaL_register(L, NULL, lib);
return 1;
}