在lua中操作C++对象的字段

luabind中注册一个c++对象,可以将那个对象作为参数传递到lua函数中,

或者作为一个c++函数的返回值返回到lua中.并且,在lua中可以直接操作

那个C++对象的数据成员.

我这几天一直在思考这是怎么实现的,因为对boost不熟悉,所以很难对

luabind的源代码作分析.经过了几天翻阅lua文档,终于想到了一个实现的

方法.

 

假设我们有以下定义:

 

 

 

  1. class A {  
  2. public:  
  3.     A(int val) : m_val(val)             { }  
  4.     ~A()                                { }  
  5.     A(const A& rhs) : m_val(rhs.m_val) { printf("c++: A::A(const A& rhs), rhs.m_val = %d/n", rhs.m_val); }  
  6.     void dump() const                     
  7.         {   
  8.             printf("c++: A::dump(), m_val = %d,m_id = %d/n", m_val,m_id);  
  9.             printf("hello/n");   
  10.         }  
  11.     static void reg(lua_State *L);  
  12. public:  
  13.     static A   *check(lua_State *L);  
  14.     static int L_dump(lua_State *L);  
  15.     static int L_setval(lua_State *L);  
  16.     static int L_tostring(lua_State *L);  
  17. public:  
  18.     int m_val;  
  19.       int m_id;  
  20. };  
 

 

我们希望可以将A的对象a传递到lua中,并且在lua中可以如下使用.

 

--in lua

function f(a)

print(a.m_val)

a.m_val = 2

end

 

为了在lua中使用C++对象,我们首先必须注册类A和A的对象.

 

 

  1. void A::reg(lua_State *L)  
  2. {  
  3.     int A, methods, mt;  
  4.     // 创建了一个表,注册了dump方法,和m_val,m_id两个字段,并给两个字段赋初值  
  5.     lua_newtable(L);  
  6.     methods = lua_gettop(L);  
  7.     lua_pushliteral(L, "dump");  
  8.     lua_pushcfunction(L, &A::L_dump);  
  9.     lua_rawset(L, methods);  
  10.         lua_pushliteral(L, "m_val");  
  11.     lua_pushnumber(L, 0);  
  12.     lua_rawset(L, methods);  
  13.         lua_pushliteral(L, "m_id");  
  14.     lua_pushnumber(L, 0);  
  15.     lua_rawset(L, methods);  
  16.     //现在我们创建一个元表,给对象使用的  
  17.     luaL_newmetatable(L, "A");  
  18.     mt = lua_gettop(L);  
  19.     //将__index的value设置成methods  
  20.     lua_pushliteral(L, "__index");  
  21.     lua_pushvalue(L, methods);  
  22.     lua_rawset(L, mt);  
  23.     //设置__newindex,这样我们就可以在lua中这样使用了:a.m_val = xxx  
  24.         lua_pushliteral(L, "__newindex");  
  25.     lua_pushcfunction(L, &A::L_setval);  
  26.     lua_rawset(L, mt);  
  27.     lua_pushliteral(L, "__tostring");  
  28.     lua_pushcfunction(L, &A::L_tostring);  
  29.     lua_rawset(L, mt);  
  30.     // construct table A,给类A使用的  
  31.     lua_newtable(L);  
  32.     A = lua_gettop(L);  
  33.     lua_pushvalue(L, methods);  
  34.     lua_setmetatable(L, A);  
  35.     lua_setglobal(L, "A");  
  36. }  
 

 

现在看看我们的main函数:

 

[c-sharp]  view plain copy print ?
  1. int _tmain(int argc, _TCHAR* argv[])  
  2. {  
  3.     lua_State *L;  
  4.     if ((L = lua_open()) == NULL) {  
  5.         printf("failed to create lua state!/n");  
  6.         exit(1);  
  7.     }  
  8.     luaL_openlibs(L);  
  9.     A::reg(L);  
  10.     if (luaL_dofile(L, "main.lua")) {  
  11.         printf("%s!/n", lua_tostring(L, -1));          
  12.         lua_close(L);  
  13.         exit(1);  
  14.     }  
  15.     printf("ok class test---------------------------------/n");  
  16.     A a(2);  
  17.     a.m_id = 3;  
  18.       
  19.     lua_getglobal(L,"process");  
  20.     int t = lua_gettop(L);  
  21.     lua_pushlightuserdata(L,&a);  
  22.      
  23.     if(lua_pcall( L, 1, 0, 0 ) != 0)  
  24.     {  
  25.     const char *str = lua_tostring(L,-1);  
  26.     std::cout << str <<std::endl;  
  27.     lua_close( L );  
  28.     getchar();  
  29.     exit(0);  
  30.     }  
  31.       
  32.     lua_close(L);  
  33.     getchar();  
  34.     exit(0);  
  35. }     
 

 

 

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稍作修改

 

 

  1. int _tmain(int argc, _TCHAR* argv[])  
  2. {  
  3.     lua_State *L;  
  4.     if ((L = lua_open()) == NULL) {  
  5.         printf("failed to create lua state!/n");  
  6.         exit(1);  
  7.     }  
  8.     luaL_openlibs(L);  
  9.     A::reg(L);  
  10.     if (luaL_dofile(L, "main.lua")) {  
  11.         printf("%s!/n", lua_tostring(L, -1));          
  12.         lua_close(L);  
  13.         exit(1);  
  14.     }  
  15.     printf("ok class test---------------------------------/n");  
  16.     A a(2);  
  17.     a.m_id = 3;  
  18.       
  19.     lua_getglobal(L,"process");  
  20.     int t = lua_gettop(L);  
  21.     lua_pushlightuserdata(L,&a);  
  22.       
  23.       
  24.     int val;   
  25.       
  26.     val = lua_gettop(L);   
  27.     lua_getfield(L, LUA_REGISTRYINDEX, "A");  
  28.     lua_setmetatable(L, val);    
  29.      
  30.     if(lua_pcall( L, 1, 0, 0 ) != 0)  
  31.     {  
  32.     const char *str = lua_tostring(L,-1);  
  33.     std::cout << str <<std::endl;  
  34.     lua_close( L );  
  35.     getchar();  
  36.     exit(0);  
  37.     }  
  38.       
  39.     lua_close(L);  
  40.     getchar();  
  41.     exit(0);  
  42. }     
 

 

 

输出:

ok class test---------------------------------

a.m_val = 0

a.m_id = 0

 

 

OK,这次我们成功的输出了,可数据却是我们设置的初始值.我们并没有把对m_val,m_id的修改反映

到lua中.

 

好的,知道了原因,我们在修改一下main. 

 

  1. int _tmain(int argc, _TCHAR* argv[])  
  2. {  
  3.     lua_State *L;  
  4.     if ((L = lua_open()) == NULL) {  
  5.         printf("failed to create lua state!/n");  
  6.         exit(1);  
  7.     }  
  8.     luaL_openlibs(L);  
  9.     A::reg(L);  
  10.     if (luaL_dofile(L, "main.lua")) {  
  11.         printf("%s!/n", lua_tostring(L, -1));          
  12.         lua_close(L);  
  13.         exit(1);  
  14.     }  
  15.     printf("ok class test---------------------------------/n");  
  16.     A a(2);  
  17.     a.m_id = 3;  
  18.       
  19.     lua_getglobal(L,"process");  
  20.     int t = lua_gettop(L);  
  21.     lua_pushlightuserdata(L,&a);  
  22.     int val;   
  23.       
  24.     val = lua_gettop(L);   
  25.     lua_getfield(L, LUA_REGISTRYINDEX, "A");  
  26.     //get table __index  
  27.     lua_pushliteral(L, "__index");  
  28.     lua_gettable(L,-2);  
  29.     //end of get table __index  
  30.     //change the m_val filed of table __index  
  31.     //设置m_val的值  
  32.     lua_pushliteral(L, "m_val");  
  33.     lua_pushnumber(L,  a.m_val);  
  34.     lua_settable(L,-3);  
  35.     //设置m_id的值  
  36.     lua_pushliteral(L, "m_id");  
  37.     lua_pushnumber(L,  a.m_id);  
  38.     lua_settable(L,-3);  
  39.     //end of change the m_val filed of table __index  
  40.     lua_pop(L,1);  
  41.     lua_setmetatable(L, val);    
  42.     if(lua_pcall( L, 1, 0, 0 ) != 0)  
  43.     {  
  44.     const char *str = lua_tostring(L,-1);  
  45.     std::cout << str <<std::endl;  
  46.         lua_close( L );  
  47.     getchar();  
  48.     exit(0);  
  49.     }  
  50.       
  51.     lua_close(L);  
  52.     getchar();  
  53.     exit(0);  
  54. }  
 

 

这次我们把m_val,和m_id的新值写入到a的元表中.

 

 

输出:

 

ok class test---------------------------------

a.m_val = 2

a.m_id = 3

 

OK,我们成功了.C++中对数据的修改成功的在lua中反映了出来.

 

下一步我们要试试在lua中修改a的数据成员了.

 

 

首先是我们的setval函数:

 

 

  1. int A::L_setval(lua_State *L)   
  2. {   
  3.     A *self;  
  4.     int val;  
  5.     self = (A *)luaL_checkudata(L, 1, "A");  
  6.     lua_getfield(L, LUA_REGISTRYINDEX, "A");  
  7.     //get table __index  
  8.     lua_pushliteral(L, "__index");  
  9.     lua_gettable(L,-2);  
  10.     //end of get table __index  
  11.     val = luaL_checkint(L, -3);  
  12.     //在这里,我们获得在lua中操作的成员名  
  13.     const char *tmp = luaL_checkstring(L, -4);  
  14.     //根据成员名,修改相应的变量  
  15.     if(strcmp("m_id",tmp) == 0)  
  16.     {  
  17.     self->m_id = val;  
  18.     //change the m_val filed of table __index  
  19.     lua_pushliteral(L, "m_id");  
  20.     lua_pushnumber(L,  self->m_id);  
  21.     lua_settable(L,-3);  
  22.     //end of change the m_val filed of table __index  
  23.     }  
  24.     else  
  25.     {  
  26.     self->m_val = val;  
  27.     //change the m_val filed of table __index  
  28.     lua_pushliteral(L, "m_val");  
  29.     lua_pushnumber(L,  self->m_val);  
  30.     lua_settable(L,-3);  
  31.     //end of change the m_val filed of table __index  
  32.     }  
  33.     lua_pop(L,1);  
  34.     lua_setmetatable(L, val);  
  35.     return 0;   
  36. }  
 

 

对于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++里面直接传递过来的对象了.

 

完整程序:

 

 

  1. #include "stdafx.h"  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <assert.h>  
  5. extern "C"  
  6. {  
  7.     #include <lua.h>  
  8.     #include <lauxlib.h>  
  9.     #include <lualib.h>  
  10. }  
  11. static void *touserdata(lua_State *L, int ud, const char *tname);  
  12. class A {  
  13. public:  
  14.     A(int val) : m_val(val)             { }  
  15.     ~A()                                { }  
  16.     A(const A& rhs) : m_val(rhs.m_val) { printf("c++: A::A(const A& rhs), rhs.m_val = %d/n", rhs.m_val); }  
  17.     void dump() const                     
  18.     {   
  19.         printf("c++: A::dump(), m_val = %d,m_id = %d/n", m_val,m_id);  
  20.         printf("hello/n");   
  21.     }  
  22.     static void reg(lua_State *L);  
  23. public:  
  24.     static A   *check(lua_State *L);  
  25.     static int L_dump(lua_State *L);  
  26.     static int L_setval(lua_State *L);  
  27.     static int L_tostring(lua_State *L);  
  28.      
  29. public:  
  30.     int m_val;  
  31.     int m_id;  
  32. };  
  33.   
  34. int _tmain(int argc, _TCHAR* argv[])  
  35. {  
  36.     lua_State *L;  
  37.     if ((L = lua_open()) == NULL) {  
  38.         printf("failed to create lua state!/n");  
  39.         exit(1);  
  40.     }  
  41.     luaL_openlibs(L);  
  42.     A::reg(L);  
  43.     if (luaL_dofile(L, "main.lua")) {  
  44.         printf("%s!/n", lua_tostring(L, -1));          
  45.         lua_close(L);  
  46.         exit(1);  
  47.     }  
  48.     printf("ok class test---------------------------------/n");  
  49.     A a(2);  
  50.     a.m_id = 3;  
  51.       
  52.     lua_getglobal(L,"process");  
  53.     lua_pushlightuserdata(L,&a);  
  54.     int val;   
  55.       
  56.     val = lua_gettop(L);   
  57.     lua_getfield(L, LUA_REGISTRYINDEX, "A");  
  58.     //get table __index  
  59.     lua_pushliteral(L, "__index");  
  60.     lua_gettable(L,-2);  
  61.     //end of get table __index  
  62.     //change the m_val filed of table __index  
  63.     //设置m_val的值  
  64.     lua_pushliteral(L, "m_val");  
  65.     lua_pushnumber(L,  a.m_val);  
  66.     lua_settable(L,-3);  
  67.     //设置m_id的值  
  68.     lua_pushliteral(L, "m_id");  
  69.     lua_pushnumber(L,  a.m_id);  
  70.     lua_settable(L,-3);  
  71.     //end of change the m_val filed of table __index  
  72.     lua_pop(L,1);  
  73.     lua_setmetatable(L, val);    
  74.     if(lua_pcall( L, 1, 0, 0 ) != 0)  
  75.     {  
  76.         const char *str = lua_tostring(L,-1);  
  77.         std::cout << str <<std::endl;  
  78.         lua_close( L );  
  79.         getchar();  
  80.         exit(0);  
  81.     }  
  82.       
  83.     lua_close(L);  
  84.     getchar();  
  85.     exit(0);  
  86. }     
  87. void *touserdata(lua_State *L, int ud, const char *tname)  
  88. {  
  89.     // the same code as luaL_checkudata except no error thrown  
  90.     void *p = lua_touserdata(L, ud);  
  91.     if (p != NULL) { /* value is a userdata? */  
  92.         if (lua_getmetatable(L, ud)) { /* does it have a metatable? */  
  93.             lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */  
  94.             if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */  
  95.                 lua_pop(L, 2); /* remove both metatables */  
  96.                 return p;  
  97.             }  
  98.         }  
  99.     }      
  100.     return NULL; /* to avoid warnings */      
  101. }  
  102. void A::reg(lua_State *L)  
  103. {  
  104.     int A, methods, mt;  
  105.     // construct table methods  
  106.     lua_newtable(L);  
  107.     methods = lua_gettop(L);  
  108.     lua_pushliteral(L, "dump");  
  109.     lua_pushcfunction(L, &A::L_dump);  
  110.     lua_rawset(L, methods);  
  111.     lua_pushliteral(L, "m_val");  
  112.     lua_pushnumber(L, 0);  
  113.     lua_rawset(L, methods);  
  114.     lua_pushliteral(L, "m_id");  
  115.     lua_pushnumber(L, 0);  
  116.     lua_rawset(L, methods);  
  117.     // construct table mt,给对象使用的  
  118.     luaL_newmetatable(L, "A");  
  119.     mt = lua_gettop(L);  
  120.     lua_pushliteral(L, "__index");  
  121.     lua_pushvalue(L, methods);  
  122.     lua_rawset(L, mt);  
  123.     lua_pushliteral(L, "__newindex");  
  124.     lua_pushcfunction(L, &A::L_setval);  
  125.     lua_rawset(L, mt);  
  126.     lua_pushliteral(L, "__tostring");  
  127.     lua_pushcfunction(L, &A::L_tostring);  
  128.     lua_rawset(L, mt);  
  129.     // construct table A,给类A使用的  
  130.     lua_newtable(L);  
  131.     A = lua_gettop(L);  
  132.     lua_pushvalue(L, methods);  
  133.     lua_setmetatable(L, A);  
  134.     lua_setglobal(L, "A");  
  135. }  
  136. A *A::check(lua_State *L)  
  137. {  
  138.     A *a;  
  139.       
  140.     // make sure type A  
  141.     a = (A *)luaL_checkudata(L, 1, "A");  
  142.     // remove self so that the argument start from 1  
  143.     lua_remove(L, 1);  
  144.     return a;  
  145. }  
  146. int A::L_dump(lua_State *L)   
  147. {   
  148.     A *self;  
  149.     self = A::check(L);  
  150.     self->dump();  
  151.     return 0;   
  152. }  
  153. int A::L_setval(lua_State *L)   
  154. {   
  155.     A *self;  
  156.     int val;  
  157.     self = (A *)luaL_checkudata(L, 1, "A");  
  158.     lua_getfield(L, LUA_REGISTRYINDEX, "A");  
  159.     //get table __index  
  160.     lua_pushliteral(L, "__index");  
  161.     lua_gettable(L,-2);  
  162.     //end of get table __index  
  163.     val = luaL_checkint(L, -3);  
  164.     const char *tmp = luaL_checkstring(L, -4);  
  165.     if(strcmp("m_id",tmp) == 0)  
  166.     {  
  167.         self->m_id = val;  
  168.         //change the m_val filed of table __index  
  169.         lua_pushliteral(L, "m_id");  
  170.         lua_pushnumber(L,  self->m_id);  
  171.         lua_settable(L,-3);  
  172.         //end of change the m_val filed of table __index  
  173.     }  
  174.     else  
  175.     {  
  176.         self->m_val = val;  
  177.         //change the m_val filed of table __index  
  178.         lua_pushliteral(L, "m_val");  
  179.         lua_pushnumber(L,  self->m_val);  
  180.         lua_settable(L,-3);  
  181.         //end of change the m_val filed of table __index  
  182.     }  
  183.     lua_pop(L,1);  
  184.     lua_setmetatable(L, val);  
  185.     return 0;   
  186. }  
  187. int A::L_tostring(lua_State *L)   
  188. {  
  189.     A *self;  
  190.     self = A::check(L);  
  191.     lua_pushfstring(L, "m_val = %d", self->m_val);  
  192.     return 1;   
  193. }  

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值