今天看到一篇文章,介绍了c++到lua的注册,感觉不错。原文地址:
#include
extern "C"
{
#include
#include
#include
}
class Base
{
public:
Base() {}
~Base() {}
int add(int a, int b)
{ return a +
b; }
};
class Foo :public Base
{
public:
Foo(lua_State *L) { printf("call Foo constructor\n"); }
~Foo() {
printf("call Foo destructor\n"); }
int foo(lua_State *L) {
printf("in foo function\n"); return 0; }
int n_add(lua_State *L)
{
int a = NULL;
int b = NULL;
a =
(int)luaL_checknumber(L, -2);
b = (int)luaL_checknumber(L, -1);
double result = add(a, b);
lua_pushnumber(L, result);
return 1;
}
static const char classname[];
static
const luna ::RegType function[];
};
/////////利用lua wipper//luaWipper.h////////////
template class Luna {
public:
static void
Register(lua_State *L) {
lua_pushcfunction(L, &Luna
::constructor);
//注册函数,在lua中创建function类型的值来表示Luna
::constructor
//该函数并将类型为fucntion的值入栈
lua_setglobal(L, T::className);
//将上面的function值赋给全局变量T::className
//在这里是将该值赋给下面的“Foo”:const
char Foo::className[] = "Foo";
luaL_newmetatable(L,
T::className);
//创建一个新表(将用作metatable),将新表放到栈顶并建立表和registry中类型名的联系。
//这个关联是双向的:使用类型名作为表的key;
//同时使用表作为类型名的key(这种双向的关联,使得其他的两个函数的实现效率更高)。
lua_pushstring(L,
"__gc");
/*
Lua以__gc元方法的方式提供了finalizers。这个元方法只对userdata类型的值有效。
当一个userdatum将被收集的时候,并且usedatum有一个__gc域,
Lua会调用这个域的值(应该是一个函数):以userdatum作为这个函数的参数调用。
这个函数负责释放与userdatum相关的所有资源。
*/
lua_pushcfunction(L,
&Luna ::gc_obj);
lua_settable(L, -3);
}
static int constructor(lua_State *L) {
T* obj = new T(L);
lua_newtable(L);
lua_pushnumber(L, 0);
T** a = (T**)lua_newuserdata(L,
sizeof(T*));
//void *lua_newuserdata (lua_State *L, size_t
size);
*a = obj;
luaL_getmetatable(L,
T::className);
//void luaL_getmetatable (lua_State *L, const
char *tname);
//函数获取registry中的tname对应的metatable。
lua_setmetatable(L, -2);
//lua_setmetatable函数将表(get到的)出栈,并将其设置为给定位置(上面userdatum)对象的metatable。
lua_settable(L, -3); // table[0] = userdatum;即table[0] = obj
for (int i = 0; T::Register[i].name; i++) {
lua_pushstring(L, T::Register[i].name);
lua_pushnumber(L,
i);
lua_pushcclosure(L, &Luna ::thunk, 1);
lua_settable(L, -3);
//table["T::Register[i].name"] = thunk;
}
return
1;
}
static int thunk(lua_State *L) {
int i = (int)lua_tonumber(L, lua_upvalueindex(1));
//当lua把C函数压入到堆栈里时会把参数存到updata里面,
//获取第一个upvalue到当前值
//函数lua_upvalueindex(实际是一个宏),用来产生一个upvalue 的假索引。
//这个假索引除了不在栈中之外,和其他的索引一样。
//表达式lua_upvalueindex(1)为第一个upvalue的索引。
lua_pushnumber(L, 0);
lua_gettable(L, 1);
T** obj = static_cast
(luaL_checkudata(L, -1, T::className));
//luaL_checkudata检查在栈中指定位置的对象是否为带有给定名字的metatable的usertatum。
//如果对象不存在正确的metatable,返回NULL(或者它不是一个userdata);
//否则,返回userdata的地址。
lua_remove(L, -1);
return
((*obj)->*(T::Register[i].mfunc))(L);
//&foo
}
static int gc_obj(lua_State *L) {
T** obj =
static_cast (luaL_checkudata(L, -1, T::className));
delete (*obj);
return 0;
}
struct
RegType {
const char *name;
int(T::*mfunc)(lua_State*);
//function pointer
};
};
///////////////////////////////luawipper.h
end//////////////////////////////
const char Foo::classname[]
= "Foo";
const luna ::RegType Foo::function[] =
{
{ "foo", &Foo::foo},
{ "add", &Foo::n_add},
{ NULL
, NULL }
};
////////////////////test.lua////////////////
/*
local f =
Foo()
f:foo()
print("add is:",f:add(5,6))
*/
////////////////////////////////////////////
//驱动程序
int main()
{
lua_State *L = lua_open();
luaopen_base(L);
luna ::Register(L);
luaL_dofile(L, "test.lua");
lua_close(L);
return 0;
}
阅读(3475) | 评论(0) | 转发(0) |