lua绑定C++对象系列二——基础模型

本篇在介绍lua绑定C++的一个最基本的模型,能够很方便的理解lua绑定C++对象后具体使用方式,主要是充分利用的元表的__index特性。

代码文件r_oo.cpp:

  1 #include <iostream>
  2 #include <cstring>
  3 #include <stdlib.h>
  4 extern "C" {
  5 #include <lua.h>
  6 #include <lualib.h>
  7 #include <lauxlib.h>
  8 }
  9 #include "comm.h"
 10 #include "luna.h"
 11 #include "lunar.h"
 12 
 13 using namespace std;
 14 
 15 class Student
 16 {
 17     public:
 18         Student(int iAge, int iScore):m_age(iAge), m_score(iScore){};
 19         ~Student(){cout<<"delete Student"<<endl;}
 20         int  getAge(){return m_age;}
 21         void setAge(int iAge){m_age = iAge;}
 22         static int autoGc(lua_State *L){
 23             Student** p = (Student**)lua_touserdata(L, 1); 
 24             cout << "auto gc. age: " << (*p)->m_age << " score: " << (*p)->m_score <<endl;
 25         }   
 26     public:
 27         int m_age;
 28         int m_score;
 29 };
 30 
 31 int create_stdent(lua_State *L)
 32 {
 33     Student** p = (Student**)lua_newuserdata(L, sizeof(Student*));
 34     *p = new Student(15, 100);
 35 
 36     luaL_getmetatable(L, "MetaStu");
 37     lua_setmetatable(L, -2);
 38 
 39     return 1;
 40 }
 41 
 42 int get_age(lua_State *L)
 43 {
 44     Student** p = (Student**)lua_touserdata(L, 1);
 45     int iAge = (*p)->getAge();
 46     lua_pushinteger(L, iAge);
 47     return 1;
 48 }
 49 
 50 int set_age(lua_State *L)
 51 {
 52     Student** p = (Student**)lua_touserdata(L, 1);
 53     int iAge = lua_tointeger(L, 2);
 54     (*p)->setAge(iAge);
 55     return 0;
 56 }
 57 
 58 int auto_gc (lua_State *L)
 59 {
 60     Student** p = (Student**)lua_touserdata(L, 1);
 61     (*p)-> autoGc(L);
 62     return 0;
 63 }
 64 
 65 int lua_openStudent(lua_State *L)
 66 {
 67     const struct luaL_Reg list[] = {{"create", create_stdent}, {NULL, NULL}};
 68     luaL_register(L, "student", list);
 69 
 70     if (luaL_newmetatable(L, "MetaStu"))
 71     {
 72         lua_pushcfunction(L, &get_age);
 73         lua_setfield(L, -2, "getAge");
 74         lua_pushcfunction(L, &set_age);
 75         lua_setfield(L, -2, "setAge");
 76         lua_pushcfunction(L, &auto_gc);
 77         lua_setfield(L, -2, "__gc");
 78         lua_pushvalue(L, -1);
 79         lua_setfield(L, -2, "__index");
 80     }
 81 
 82     return 1;
 83 }
 84 
 85 int main(int argc, char* argv[])
 86 {
 87     lua_State *L = luaL_newstate();
 88     luaL_openlibs(L);
 89     luaL_dofile(L, "tree.lua");
 90 
 91     //bind to object use metatable
 92     lua_openStudent(L);
 93     print_stack(L);
 94 
 95     luaL_dofile(L, "r_oo.lua");
 96     print_stack(L);
 97     lua_settop(L, 0);
 98     lua_close(L);
 99     return 0;
100 }

如上,主要思路有2步:

1、  lua_openStudent。只执行一次。

  •  注册一个create_student的函数,方便在lua中调用student.create_student()创建student对象。注意,这时create_student创建的是一个userdata结构,存放C++ student的对象指针。
  •  针对Student类生成一个全局的元表结构MetaStu, 注册一些元表函数类似setAge, getAge, setScore, getScore等,并且把__index指向元表本身。这样后期通过userdata调用方法时,可以自动在元表中进行查找,看起来更符合OO的使用特点。

  

 

2、  create_student。按需调用,多次调用创建不同的student对象实例。并且设置userdata的元表为MetaStu。

对应执行的r_oo.lua:

do
local stu = student.create();
print_tree(stu);
print_metatable(stu);
local age = stu:getAge();
stu:setAge(18);
local age2 = stu:getAge();
print("old: " .. age .. " new: " .. age2);

print ""
stu.setAge(stu,19)
print("old: " .. age .. " new: " .. stu:getAge(stu));
end
collectgarbage("collect");

如上所示:这里使用了stu:setAge(18)和std. setAge (stu,19),实际是因为在使用:符号时,系统默认把对象本身作为第一个参数传入,不用再显示,两者语法效果其实是一样的。

 

代码执行结果如下:

==========Total:2==========
idx:-1 type:5(table) 0x23ca830
idx:-2 type:5(table) 0x23ca8c0
===========================
MetaStu: 0x23c9e38
not a table
table: 0x23ca830
getScore function: 0x402b16
setAge  function: 0x4027be
setScore function: 0x402b5a
__index table: 0x23ca830+
__gc    function: 0x402ba8
getAge  function: 0x40276f
__name  MetaStu
old: 15 new: 18

old: 15 new: 19
auto gc. age: 19 score: 100
==========Total:2==========
idx:-1 type:5(table) 0x23ca830
idx:-2 type:5(table) 0x23ca8c0
===========================

如上所示:红色标记的就是print_metatable(stu)打印userdata元表的情况。gc垃圾收集会调用注册的__gc元方法,Student::autoGc被成功调用。

 

总结一下:这是让lua绑定C++对象的最基本模型。使用新创建userdata存放C++对象实例指针,并针对userdata设置元表,元表中注册各种C++的方法,并让__index指向元表自身,这样当使用诸如stu.setAge时,会通过__index指向的table进行索引,当__index指向自身就直接索引自身即可。这样在lua中创建userdata后,create_student接口也会自动创建C++对象关联在一起,并且在使用userdata过程中可以像C++引用成员方法一样去使用。

 

posted @ 2018-10-15 15:50  liao0001  阅读(769)  评论(0编辑  收藏  举报