zoukankan      html  css  js  c++  java
  • <转> lua: userdata的metatable使用

    1 如何封装c++的指针

    对于c++对象的lua包装,我们可以使用

     template<typename T>
     struct luaUserdataWrapper
     {
      luaUserdataWrapper() {}
      luaUserdataWrapper(const T& d) : data(d) {}

      T data; 
     };

    class CObject

    {

    public:

       int v[10];
    };

    typedef luaUserdataWrapper<CObject*> luaObject;

    这样就可以在c代码中,按照如下方法向lua中添加生成CObject的对象的C函数:

    int NewObject( lua_State* L )

    {

     luaObject* wrapper = (luaObject*) lua_newuserdata( L, sizeof(luaObject) );

     wrapper->data = new CObject;

     return 1;
    }

    lua_newuserdata函数把wrapper存放在栈顶位置,作为NewObject的返回值。

    wrapper的生存期由lua负责,而wrapper->data的生命期则由程序员自己负责。

    在lua代码中的使用方法是:

    obj = NewObject() --调用C函数

    2 使用metatable

    如果此时我们想在lua中使用如下语法:

    obj[5]=20

    value = obj[5]

    则需要我们为luaObject添加metatable属性。

    步骤1:

    在lua代码中的普通表,不能作为userdata的metatable。必须使用luaL_newmetatable创建的表才能作为userdata的metatable。

    在openlib函数中,添加一个userdata 的 metatable表,

    int OnOpenlib( lua_State* L )

    {

    ...

    luaL_newmetatable( L, “ObjectMetatable");

    }

    luaL_newmetatable把新创建的表放在栈顶。

    注意:新创建的ObjectMetatable表仅在栈中被声明,并没有加入到lua代码中。如果在以后的lua代码中使用ObjectMetatable.__index等操作,会提示ObjectMetatable:a nil value。

    步骤2:

    这是我们重写上面的New方法。

    int NewObject( lua_State* L )

    {

     luaObject* wrapper = (luaObject*) lua_newuserdata( L, sizeof(luaObject) );

     wrapper->data = new CObject;

     luaL_getmetatable( L, ”ObjectMetatable“);
     lua_setmetatable( L, -2 );

     return 1;
    }

    这样我们就为新生成的luaObject对象添加metatable。

    luaL_getmetatable( L, ”ObjectMetatable“)获取ObjectMetatable表,并放入栈顶。

    lua_setmetatable( L, -2 )则把新生成的userdata的metatable设置为ObjectMetatable。

    步骤3:

    value = obj[5]的取下标操作对应的是__index域,而

    obj[5]=2;对应的是__newindex域。

    所以我们需要添加ObjectMetatable的__index,__newindex域。

    我们重写int OnOpenlib( lua_State* L )方法

    int OnOpenlib( lua_State* L )

    {

    ...

    luaL_newmetatable( L, “ObjectMetatable");

    lua_pushstring( L, "__index" );
     lua_pushcfunction( L, GetValue );
     lua_rawset( L, -3 ); // ObjectMetatable.__index = GetHorizonValue

     lua_pushstring( L, "__newindex" );
     lua_pushcfunction( L, SetValue );

    lua_rawset( L, -3 ); // ObjectMetatable.__newindex = GetHorizonValue

    }

    GetValue 与SetValue 是自定义的C函数,可以不用被注册到lua代码中。

    在lua中调用

    v=obj[5]

    时,会触发元函数metatable.__index,obj、5会被依次入栈。

    所以GetValue方法我们可以写为

    int GetValue(lua_State* L)

    {

    luaL_checktype(L, -1, LUA_TNUMBER);
     luaL_checktype(L, -2, LUA_TUSERDATA);

     luaObject* wrapper = (luaObject*)   lua_touserdata(L, -2);

     ASSERT( wrapper->data != NULL );
     if ( wrapper->data == NULL )
     {
      lua_pushstring( L, "GetHorizonValue: NULL wrapper " );
      lua_error(L);
      return 1;
     }

     int index = (int)(float)lua_tonumber(L, -1);

     int value = wrapper->data.v[index];

    lua_pushnumber( L, value );

    return 1;

    }

  • 相关阅读:
    NLP概览(一)
    java正则表达式实例
    notepad++
    Mybatis点滴
    (转)GNU Make学习总结(二)
    (转)GNU Make学习总结(一)
    分页查询
    第三方插件
    单例模式读取数据库配置文件和JNDI连接数据源
    过滤器与监听器
  • 原文地址:https://www.cnblogs.com/zhangdongsheng/p/3653303.html
Copyright © 2011-2022 走看看