<转> 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;
}
<转> lua: userdata的metatable使用的更多相关文章
- Lua的Full UserData、Light UserData和metatable
http://lua.2524044.n2.nabble.com/LightUserData-and-metatables-td3807698.html https://www.lua.org/man ...
- Lua基础之MetaTable(6)
Lua基础之MetaTable(6) 转载地址:http://nova-fusion.com/2011/06/30/lua-metatables-tutorial/ 关于MetaTable的补充:ht ...
- Lua的元表(metatable)
metatable允许我们改变table的行为 > Lua中的每一个表都可以有metatable(后面我们将看到userdata也有Metatable) > Lua默认创建一个不带meta ...
- Lua中的metatable详解
转自:http://www.jb51.net/article/56690.htm Lua 中 metatable 是一个普通的 table,但其主要有以下几个功能: 1.定义算术操作符和关系操作符的行 ...
- Lua 安全调用 metatable 的简单应用
事情的经过 我们的项目中存在好几个战斗界面,不过界面中的内容略有不同.跟同事出去吃饭的时候,他问我.我们现在的战斗界面.有很多是重复的,但是也有偶尔几个地方不太一样.我在战斗过程中驱动这些界面的时候. ...
- lua中的metatable和metamethod
--元表和元方法给lua里的值设定一些操作,让我们可以对这些操作自定义 --创建一个新的table变量时,它是不存在元表的 --在Lua中,只能设置table的元表,其他类型的值的元表,只能通过C代码 ...
- lua userdata
#define metatablename "studentlib.06-11-11" /** * utility functions */ static int pusherro ...
- Lua 与 C 交互之UserData(4)
lua作为脚本于要能够使用宿主语言的类型,不管是宿主基本的或者扩展的类型结构,所以Lua提供的UserData来满足扩展的需求.在Lua中使用宿主语言的类型至少要考虑到几个方面: 数据内存 生命周期 ...
- Lua C++交互 应用实例步骤(UserData使用)
一.配置Lua C++交互环境 1.下载Lua 包环境 地址: https://www.lua.org/download.html ,我们这里用的是5.4.2版本. 2.新建C++ 控制台应用程序 3 ...
随机推荐
- PHP的Trait
PHP的Trait Trait是在PHP5.4中加入的,它既不是接口也不是类.主要是为了解决单继承语言的限制.是PHP多重继承的一种解决方案.例如,需要同时继承两个 Abstract Class, 这 ...
- 使用graphql和apollo client构建react web应用
graphql是一种用于 API 的查询语言(摘自官网). 我们为什么要用graphql? 相信大家在开发web应用的时候常常会遇到以下这些问题:后端更新了接口却没有通知前端,从而导致各种报错:后端修 ...
- 大数据技术之_16_Scala学习_06_面向对象编程-高级+隐式转换和隐式值
第八章 面向对象编程-高级8.1 静态属性和静态方法8.1.1 静态属性-提出问题8.1.2 基本介绍8.1.3 伴生对象的快速入门8.1.4 伴生对象的小结8.1.5 最佳实践-使用伴生对象解决小孩 ...
- UVALive - 3211 (2-SAT + 二分)
layout: post title: 训练指南 UVALive - 3211 (2-SAT + 二分) author: "luowentaoaa" catalog: true m ...
- noi题库 1.7 字符串 10到第15题
10:简单密码 描述 Julius Caesar曾经使用过一种很简单的密码.对于明文中的每个字符,将它用它字母表中后5位对应的字符来代替,这样就得到了密文.比如字符A用F来代替.如下是密文和明文中字符 ...
- ( 转 ) .net 操作 JWT
GitHub: https://github.com/jwt-dotnet/jwt 1.JWT定义 JWT(Json Web Token)是一种用于双方之间传递安全信息的简洁的.URL安全的表述性声明 ...
- [BZOJ2111][ZJOI2010]Perm排列计数(组合数学)
题意就是求一个n个点的堆的合法形态数. 显然,给定堆中所有数的集合,则这个堆的根是确定的,而由于堆是完全二叉树,所以每个点左右子树的大小也是确定的. 设以i为根的堆的形态数为F(i),所以F(i)+= ...
- Miller-Rabin与Pollard-Rho备忘
Miller-Rabin素性测试算法: 根据费马小定理当p为素数时成立,所以如果存在一个a使x不满足此定理,则x必然不为素数. 但这是充分条件而不是必要条件,所以对于每个a,可能存在满足定理的x,这时 ...
- 「Baltic2015」Network
题目描述 原文 The government of Byteland has decided that it is time to connect their little country to th ...
- 【dfs】【哈希表】bzoj2783 [JLOI2012]树
因为所有点权都是正的,所以对每个结点u来说,每条从根到它的路径上只有最多一个结点v符合d(u,v)=S. 所以我们可以边dfs边把每个结点的前缀和pre[u]存到一个数据结构里面,同时查询pre[u] ...