如何实现面向对象?
熟悉Lua的同学都知道!在Lua内部已经实现了面向对象的基本机制(table);
同时也为宿主语言(在这里是C语言)提供了一套自定义数据结构(userdata)。所以,我们可以简单的利用metatable与__index的访问机制,为userdata实现一套简单的面向对象的访问方式。
stu.c
#include#include #include typedef struct _Student{ const char * strName ; // 学生姓名 int strNum ; // 学号 int iSex ; // 学生性别 int iAge ; // 学生年龄}Student;int lnew(lua_State* L){ Student *stu = lua_newuserdata(L,sizeof(Student)); if(NULL == stu){ return 0; } luaL_setmetatable(L,"stu"); return 1;}int lset(lua_State* L){ Student *stu = luaL_checkudata(L,1,"stu"); stu->strName = luaL_checkstring(L,2); stu->strNum = luaL_checkinteger(L,3); stu->iSex = luaL_checkinteger(L,4); stu->iAge = luaL_checkinteger(L,5); return 0;}int lget(lua_State* L){ Student *stu = luaL_checkudata(L,1,"stu"); lua_pushstring(L,stu->strName); lua_pushinteger(L,stu->strNum); lua_pushinteger(L,stu->iSex); lua_pushinteger(L,stu->iAge); return 4;}const luaL_Reg mylib[] = { {"new",lnew}, {"set",lset}, {"get",lget}, {NULL,NULL}};LUA_API int luaopen_stu(lua_State* L){ luaL_newmetatable(L,"stu"); lua_pushstring (L,"__index"); lua_pushvalue(L,-2); lua_rawset(L,-3); luaL_setfuncs(L,mylib,0); luaL_newlib(L,mylib); return 1;}
main.lua
local stu = require "stu"local stu = stu.new()print(stu)stu:set("Candy",1024,1,26)local name,id,sex,age = stu:get()print(name,id,sex,age)
运行结果:
[root@localhost ~]# cc -o stu.so stu.c -Wall -O2 -fPIC -shared -std=gnu99[root@localhost ~]# lua main.lua stu: 0x19380d8Candy 1024 1 26[root@localhost ~]#
运行结果很简单。现在,我们简要分析一下具体实现步奏。
首先我们在注册表创建了一个metatable,并且起名"stu"。
然后为这个元表添加一个__index元方法,然后将自身作为键值查找域。
最后使用setfuncs为元表注入方法。
上述步奏等效于lua中如下操作:
local meta = {1,2,3}local t = setmetatable({},{__index=meta})print(t[1])
这里需要注意的是:
full userdata的生命周期是由Lua来管理的。
如果由Lua gc回收了userdata的使用空间,C语言还引用原地址将会引起段错误。
所以如果需要完全使用C API来管理 userdata是生命周期,请使用light userdata。