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;

}

<转> lua: userdata的metatable使用的更多相关文章

  1. Lua的Full UserData、Light UserData和metatable

    http://lua.2524044.n2.nabble.com/LightUserData-and-metatables-td3807698.html https://www.lua.org/man ...

  2. Lua基础之MetaTable(6)

    Lua基础之MetaTable(6) 转载地址:http://nova-fusion.com/2011/06/30/lua-metatables-tutorial/ 关于MetaTable的补充:ht ...

  3. Lua的元表(metatable)

    metatable允许我们改变table的行为 > Lua中的每一个表都可以有metatable(后面我们将看到userdata也有Metatable) > Lua默认创建一个不带meta ...

  4. Lua中的metatable详解

    转自:http://www.jb51.net/article/56690.htm Lua 中 metatable 是一个普通的 table,但其主要有以下几个功能: 1.定义算术操作符和关系操作符的行 ...

  5. Lua 安全调用 metatable 的简单应用

    事情的经过 我们的项目中存在好几个战斗界面,不过界面中的内容略有不同.跟同事出去吃饭的时候,他问我.我们现在的战斗界面.有很多是重复的,但是也有偶尔几个地方不太一样.我在战斗过程中驱动这些界面的时候. ...

  6. lua中的metatable和metamethod

    --元表和元方法给lua里的值设定一些操作,让我们可以对这些操作自定义 --创建一个新的table变量时,它是不存在元表的 --在Lua中,只能设置table的元表,其他类型的值的元表,只能通过C代码 ...

  7. lua userdata

    #define metatablename "studentlib.06-11-11" /** * utility functions */ static int pusherro ...

  8. Lua 与 C 交互之UserData(4)

    lua作为脚本于要能够使用宿主语言的类型,不管是宿主基本的或者扩展的类型结构,所以Lua提供的UserData来满足扩展的需求.在Lua中使用宿主语言的类型至少要考虑到几个方面: 数据内存 生命周期 ...

  9. Lua C++交互 应用实例步骤(UserData使用)

    一.配置Lua C++交互环境 1.下载Lua 包环境 地址: https://www.lua.org/download.html ,我们这里用的是5.4.2版本. 2.新建C++ 控制台应用程序 3 ...

随机推荐

  1. MVC模型绑定

    在项目中使用MVC的时候,我们无需像WebForm那样手动获取值再赋值到Model上,这得益于MVC的模型绑定,下面就介绍下复杂类型的模型绑定 Controller: public class Hom ...

  2. 内存可见性,指令重排序,JIT。。。。。。从一个知乎问题谈起

    在知乎上看到一个问题<java中volatile关键字的疑惑?>,引起了我的兴趣 问题是这样的: package com.cc.test.volatileTest; public clas ...

  3. [jquery] ajax 调试

    $.ajax({ type: ‘post’, url: url, data: {code: ‘15′}, dataType: ‘jsonp’, sccuess:function(data){ aler ...

  4. Codeforces 651 B. Beautiful Paintings

    B. Beautiful Paintings   time limit per test 1 second memory limit per test 256 megabytes input stan ...

  5. (2)C# 创建ef oracle

    1.NUGet下载 2.下载  Oracle Developer Tools for Visual Studio https://www.oracle.com/technetwork/develope ...

  6. 洛谷 P1316 丢瓶盖【二分答案】

    题目描述 陶陶是个贪玩的孩子,他在地上丢了A个瓶盖,为了简化问题,我们可以当作这A个瓶盖丢在一条直线上,现在他想从这些瓶盖里找出B个,使得距离最近的2个距离最大,他想知道,最大可以到多少呢? 输入输出 ...

  7. rsync用于同步目录

    rsync是unix/linux下同步文件的一个高效算法,它能同步更新两处计算机的文件与目录,并适当利用查找文件中的不同块以减少数据传输.rsync中一项与其他大部分类似程序或协定中所未见的重要特性是 ...

  8. [CF494C]Helping People

    题意:有$n$个穷人,每个穷人有$a_i$的钱,有一个富人决定做$q$次捐赠$(l_i,r_i,p_i)$,表示他有$p_i$的概率给$[l_i,r_i]$的人捐$1$的钱,捐赠的价值为捐赠后最富的人 ...

  9. 【枚举】Codeforces Round #394 (Div. 2) C. Dasha and Password

    纪念死去的智商(虽然本来就没有吧……) 三重循环枚举将哪三个fix string作为数字.字母和符号位.记下最小的值就行了. 预处理之后这个做法应该是O(n^3)的,当然完全足够.不预处理是O(n^3 ...

  10. 【对询问分块】CODEVS1080 线段树练习

    #include<cstdio> #include<cmath> using namespace std; #define N 100001 int sum[N],a[N],n ...