zoukankan      html  css  js  c++  java
  • 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++引用成员方法一样去使用。

     

  • 相关阅读:
    命令行编译运行java工程(转)
    JAVA配置环境变量的意义(转)
    在Linux环境下搭建Tomcat+mysql+jdk环境(转)
    java环境变量
    varchar(8000) nvarchar(4000) varchar(max) nvarchar(max) 区别
    HTTP与HTTPS握手的那些事(转载)
    ELK研究-部署搭建运用
    主机规划与磁盘分区
    占位符问题 python pymysql
    django 数据迁移的问题 sqlite3 --> mysql
  • 原文地址:https://www.cnblogs.com/liao0001/p/9791290.html
Copyright © 2011-2022 走看看