打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
在lua中操作C++对象的字段(转)
luabind中注册一个c++对象,可以将那个对象作为参数传递到lua函数中,
或者作为一个c++函数的返回值返回到lua中.并且,在lua中可以直接操作
那个C++对象的数据成员.
我这几天一直在思考这是怎么实现的,因为对boost不熟悉,所以很难对
luabind的源代码作分析.经过了几天翻阅lua文档,终于想到了一个实现的
方法.
假设我们有以下定义:
[cpp] view plaincopy
class A {
public:
A(int val) : m_val(val)             { }
~A()                                { }
A(const A& rhs) : m_val(rhs.m_val) { printf("c++: A::A(const A& rhs), rhs.m_val = %d/n", rhs.m_val); }
void dump() const
{
printf("c++: A::dump(), m_val = %d,m_id = %d/n", m_val,m_id);
printf("hello/n");
}
static void reg(lua_State *L);
public:
static A   *check(lua_State *L);
static int L_dump(lua_State *L);
static int L_setval(lua_State *L);
static int L_tostring(lua_State *L);
public:
int m_val;
int m_id;
};
我们希望可以将A的对象a传递到lua中,并且在lua中可以如下使用.
--in lua
function f(a)
print(a.m_val)
a.m_val = 2
end
为了在lua中使用C++对象,我们首先必须注册类A和A的对象.
[cpp] view plaincopy
void A::reg(lua_State *L)
{
int A, methods, mt;
// 创建了一个表,注册了dump方法,和m_val,m_id两个字段,并给两个字段赋初值
lua_newtable(L);
methods = lua_gettop(L);
lua_pushliteral(L, "dump");
lua_pushcfunction(L, &A::L_dump);
lua_rawset(L, methods);
lua_pushliteral(L, "m_val");
lua_pushnumber(L, 0);
lua_rawset(L, methods);
lua_pushliteral(L, "m_id");
lua_pushnumber(L, 0);
lua_rawset(L, methods);
//现在我们创建一个元表,给对象使用的
luaL_newmetatable(L, "A");
mt = lua_gettop(L);
//将__index的value设置成methods
lua_pushliteral(L, "__index");
lua_pushvalue(L, methods);
lua_rawset(L, mt);
//设置__newindex,这样我们就可以在lua中这样使用了:a.m_val = xxx
lua_pushliteral(L, "__newindex");
lua_pushcfunction(L, &A::L_setval);
lua_rawset(L, mt);
lua_pushliteral(L, "__tostring");
lua_pushcfunction(L, &A::L_tostring);
lua_rawset(L, mt);
// construct table A,给类A使用的
lua_newtable(L);
A = lua_gettop(L);
lua_pushvalue(L, methods);
lua_setmetatable(L, A);
lua_setglobal(L, "A");
}
现在看看我们的main函数:
[c-sharp] view plaincopy
int _tmain(int argc, _TCHAR* argv[])
{
lua_State *L;
if ((L = lua_open()) == NULL) {
printf("failed to create lua state!/n");
exit(1);
}
luaL_openlibs(L);
A::reg(L);
if (luaL_dofile(L, "main.lua")) {
printf("%s!/n", lua_tostring(L, -1));
lua_close(L);
exit(1);
}
printf("ok class test---------------------------------/n");
A a(2);
a.m_id = 3;
lua_getglobal(L,"process");
int t = lua_gettop(L);
lua_pushlightuserdata(L,&a);
if(lua_pcall( L, 1, 0, 0 ) != 0)
{
const char *str = lua_tostring(L,-1);
std::cout << str <<std::endl;
lua_close( L );
getchar();
exit(0);
}
lua_close(L);
getchar();
exit(0);
}
main.lua
function process(a)
print('a.m_val = ' .. a.m_val);
print('a.m_id = ' .. a.m_id);
a:dump();
end
输出:
ok class test---------------------------------
main.lua:4: attempt to index local 'a' (a userdata value)
奥,在这里我们仍然无法在lua中直接使用从C++中传递过来的a对象,
为什么呢,我们不是已经注册了a的元方法了吗.
恩,对main稍作修改
[cpp] view plaincopy
int _tmain(int argc, _TCHAR* argv[])
{
lua_State *L;
if ((L = lua_open()) == NULL) {
printf("failed to create lua state!/n");
exit(1);
}
luaL_openlibs(L);
A::reg(L);
if (luaL_dofile(L, "main.lua")) {
printf("%s!/n", lua_tostring(L, -1));
lua_close(L);
exit(1);
}
printf("ok class test---------------------------------/n");
A a(2);
a.m_id = 3;
lua_getglobal(L,"process");
int t = lua_gettop(L);
lua_pushlightuserdata(L,&a);
int val;
val = lua_gettop(L);
lua_getfield(L, LUA_REGISTRYINDEX, "A");
lua_setmetatable(L, val);
if(lua_pcall( L, 1, 0, 0 ) != 0)
{
const char *str = lua_tostring(L,-1);
std::cout << str <<std::endl;
lua_close( L );
getchar();
exit(0);
}
lua_close(L);
getchar();
exit(0);
}
输出:
ok class test---------------------------------
a.m_val = 0
a.m_id = 0
OK,这次我们成功的输出了,可数据却是我们设置的初始值.我们并没有把对m_val,m_id的修改反映
到lua中.
好的,知道了原因,我们在修改一下main.
[cpp] view plaincopy
int _tmain(int argc, _TCHAR* argv[])
{
lua_State *L;
if ((L = lua_open()) == NULL) {
printf("failed to create lua state!/n");
exit(1);
}
luaL_openlibs(L);
A::reg(L);
if (luaL_dofile(L, "main.lua")) {
printf("%s!/n", lua_tostring(L, -1));
lua_close(L);
exit(1);
}
printf("ok class test---------------------------------/n");
A a(2);
a.m_id = 3;
lua_getglobal(L,"process");
int t = lua_gettop(L);
lua_pushlightuserdata(L,&a);
int val;
val = lua_gettop(L);
lua_getfield(L, LUA_REGISTRYINDEX, "A");
//get table __index
lua_pushliteral(L, "__index");
lua_gettable(L,-2);
//end of get table __index
//change the m_val filed of table __index
//设置m_val的值
lua_pushliteral(L, "m_val");
lua_pushnumber(L,  a.m_val);
lua_settable(L,-3);
//设置m_id的值
lua_pushliteral(L, "m_id");
lua_pushnumber(L,  a.m_id);
lua_settable(L,-3);
//end of change the m_val filed of table __index
lua_pop(L,1);
lua_setmetatable(L, val);
if(lua_pcall( L, 1, 0, 0 ) != 0)
{
const char *str = lua_tostring(L,-1);
std::cout << str <<std::endl;
lua_close( L );
getchar();
exit(0);
}
lua_close(L);
getchar();
exit(0);
}
这次我们把m_val,和m_id的新值写入到a的元表中.
输出:
ok class test---------------------------------
a.m_val = 2
a.m_id = 3
OK,我们成功了.C++中对数据的修改成功的在lua中反映了出来.
下一步我们要试试在lua中修改a的数据成员了.
首先是我们的setval函数:
[cpp] view plaincopy
int A::L_setval(lua_State *L)
{
A *self;
int val;
self = (A *)luaL_checkudata(L, 1, "A");
lua_getfield(L, LUA_REGISTRYINDEX, "A");
//get table __index
lua_pushliteral(L, "__index");
lua_gettable(L,-2);
//end of get table __index
val = luaL_checkint(L, -3);
//在这里,我们获得在lua中操作的成员名
const char *tmp = luaL_checkstring(L, -4);
//根据成员名,修改相应的变量
if(strcmp("m_id",tmp) == 0)
{
self->m_id = val;
//change the m_val filed of table __index
lua_pushliteral(L, "m_id");
lua_pushnumber(L,  self->m_id);
lua_settable(L,-3);
//end of change the m_val filed of table __index
}
else
{
self->m_val = val;
//change the m_val filed of table __index
lua_pushliteral(L, "m_val");
lua_pushnumber(L,  self->m_val);
lua_settable(L,-3);
//end of change the m_val filed of table __index
}
lua_pop(L,1);
lua_setmetatable(L, val);
return 0;
}
对于set函数我们要注意一点,更改完成员变量后,我们又修改了对象的元表,
以把这种改变反映到lua中去.
新的main.lua
function process(a)
print('a.m_val = ' .. a.m_val);
print('a.m_id = ' .. a.m_id);
a.m_val = 1;
a.m_id = 4;
print('a.m_val = ' .. a.m_val);
print('a.m_id = ' .. a.m_id);
end
输出:
ok class test---------------------------------
a.m_val = 2
a.m_id = 3
a.m_val = 1
a.m_id = 4
啊,我们成功了,现在我们可以在lua中直接操作从c++里面直接传递过来的对象了.
完整程序:
[cpp] view plaincopy
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
static void *touserdata(lua_State *L, int ud, const char *tname);
class A {
public:
A(int val) : m_val(val)             { }
~A()                                { }
A(const A& rhs) : m_val(rhs.m_val) { printf("c++: A::A(const A& rhs), rhs.m_val = %d/n", rhs.m_val); }
void dump() const
{
printf("c++: A::dump(), m_val = %d,m_id = %d/n", m_val,m_id);
printf("hello/n");
}
static void reg(lua_State *L);
public:
static A   *check(lua_State *L);
static int L_dump(lua_State *L);
static int L_setval(lua_State *L);
static int L_tostring(lua_State *L);
public:
int m_val;
int m_id;
};
int _tmain(int argc, _TCHAR* argv[])
{
lua_State *L;
if ((L = lua_open()) == NULL) {
printf("failed to create lua state!/n");
exit(1);
}
luaL_openlibs(L);
A::reg(L);
if (luaL_dofile(L, "main.lua")) {
printf("%s!/n", lua_tostring(L, -1));
lua_close(L);
exit(1);
}
printf("ok class test---------------------------------/n");
A a(2);
a.m_id = 3;
lua_getglobal(L,"process");
lua_pushlightuserdata(L,&a);
int val;
val = lua_gettop(L);
lua_getfield(L, LUA_REGISTRYINDEX, "A");
//get table __index
lua_pushliteral(L, "__index");
lua_gettable(L,-2);
//end of get table __index
//change the m_val filed of table __index
//设置m_val的值
lua_pushliteral(L, "m_val");
lua_pushnumber(L,  a.m_val);
lua_settable(L,-3);
//设置m_id的值
lua_pushliteral(L, "m_id");
lua_pushnumber(L,  a.m_id);
lua_settable(L,-3);
//end of change the m_val filed of table __index
lua_pop(L,1);
lua_setmetatable(L, val);
if(lua_pcall( L, 1, 0, 0 ) != 0)
{
const char *str = lua_tostring(L,-1);
std::cout << str <<std::endl;
lua_close( L );
getchar();
exit(0);
}
lua_close(L);
getchar();
exit(0);
}
void *touserdata(lua_State *L, int ud, const char *tname)
{
// the same code as luaL_checkudata except no error thrown
void *p = lua_touserdata(L, ud);
if (p != NULL) { /* value is a userdata? */
if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */
lua_pop(L, 2); /* remove both metatables */
return p;
}
}
}
return NULL; /* to avoid warnings */
}
void A::reg(lua_State *L)
{
int A, methods, mt;
// construct table methods
lua_newtable(L);
methods = lua_gettop(L);
lua_pushliteral(L, "dump");
lua_pushcfunction(L, &A::L_dump);
lua_rawset(L, methods);
lua_pushliteral(L, "m_val");
lua_pushnumber(L, 0);
lua_rawset(L, methods);
lua_pushliteral(L, "m_id");
lua_pushnumber(L, 0);
lua_rawset(L, methods);
// construct table mt,给对象使用的
luaL_newmetatable(L, "A");
mt = lua_gettop(L);
lua_pushliteral(L, "__index");
lua_pushvalue(L, methods);
lua_rawset(L, mt);
lua_pushliteral(L, "__newindex");
lua_pushcfunction(L, &A::L_setval);
lua_rawset(L, mt);
lua_pushliteral(L, "__tostring");
lua_pushcfunction(L, &A::L_tostring);
lua_rawset(L, mt);
// construct table A,给类A使用的
lua_newtable(L);
A = lua_gettop(L);
lua_pushvalue(L, methods);
lua_setmetatable(L, A);
lua_setglobal(L, "A");
}
A *A::check(lua_State *L)
{
A *a;
// make sure type A
a = (A *)luaL_checkudata(L, 1, "A");
// remove self so that the argument start from 1
lua_remove(L, 1);
return a;
}
int A::L_dump(lua_State *L)
{
A *self;
self = A::check(L);
self->dump();
return 0;
}
int A::L_setval(lua_State *L)
{
A *self;
int val;
self = (A *)luaL_checkudata(L, 1, "A");
lua_getfield(L, LUA_REGISTRYINDEX, "A");
//get table __index
lua_pushliteral(L, "__index");
lua_gettable(L,-2);
//end of get table __index
val = luaL_checkint(L, -3);
const char *tmp = luaL_checkstring(L, -4);
if(strcmp("m_id",tmp) == 0)
{
self->m_id = val;
//change the m_val filed of table __index
lua_pushliteral(L, "m_id");
lua_pushnumber(L,  self->m_id);
lua_settable(L,-3);
//end of change the m_val filed of table __index
}
else
{
self->m_val = val;
//change the m_val filed of table __index
lua_pushliteral(L, "m_val");
lua_pushnumber(L,  self->m_val);
lua_settable(L,-3);
//end of change the m_val filed of table __index
}
lua_pop(L,1);
lua_setmetatable(L, val);
return 0;
}
int A::L_tostring(lua_State *L)
{
A *self;
self = A::check(L);
lua_pushfstring(L, "m_val = %d", self->m_val);
return 1;
}
更多
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
和我一起写lua - C和lua的参数传递与返回值
Redis源码学习:Lua脚本
luajit FFI LUA脚本中怎样调用C自己定义的函数
lua和c/c 互相调用实例分析 - lxyfirst - C 博客
lua调用C++写的DLL实现“热更新”
【教程2】MongoDB学习笔记(三) —— 在MVC模式下通过Jqgrid表格操作MongoDB数据
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服