Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7175173
  • 博文数量: 510
  • 博客积分: 12019
  • 博客等级: 上将
  • 技术积分: 6836
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-01 16:46
文章分类

全部博文(510)

文章存档

2022年(2)

2021年(6)

2020年(59)

2019年(4)

2018年(10)

2017年(5)

2016年(2)

2015年(4)

2014年(4)

2013年(16)

2012年(47)

2011年(65)

2010年(46)

2009年(34)

2008年(52)

2007年(52)

2006年(80)

2005年(22)

分类: C/C++

2010-09-26 18:31:49

今天看到一篇文章,介绍了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;
}
阅读(3413) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~