如何实现面向对象?

 

    熟悉Lua的同学都知道!在Lua内部已经实现了面向对象的基本机制(table);

    同时也为宿主语言(在这里是C语言)提供了一套自定义数据结构(userdata)。所以,我们可以简单的利用metatable与__index的访问机制,为userdata实现一套简单的面向对象的访问方式。

 

stu.c

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>


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: 0x19380d8
Candy	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。

转载于:https://my.oschina.net/CandyMi/blog/1305292

更多推荐