<轉> lua: userdata的metatable使用

1 如何封裝c++的指針c++

 

對於c++對象的lua包裝,咱們能夠使用程序員

 template<typename T>
 struct luaUserdataWrapper
 {
  luaUserdataWrapper() {}
  luaUserdataWrapper(const T& d) : data(d) {}app

  T data; 
 };函數

class CObjectlua

{指針

public:對象

   int v[10];
};get

typedef luaUserdataWrapper<CObject*> luaObject;string

這樣就能夠在c代碼中,按照以下方法向lua中添加生成CObject的對象的C函數:io

int NewObject( lua_State* L )

{

 luaObject* wrapper = (luaObject*) lua_newuserdata( L, sizeof(luaObject) );

 wrapper->data = new CObject;

 return 1;
}

lua_newuserdata函數把wrapper存放在棧頂位置,做爲NewObject的返回值。

wrapper的生存期由lua負責,而wrapper->data的生命期則由程序員本身負責。

在lua代碼中的使用方法是:

obj = NewObject() --調用C函數

 

2 使用metatable

若是此時咱們想在lua中使用以下語法:

obj[5]=20

value = obj[5]

則須要咱們爲luaObject添加metatable屬性。

步驟1:

在lua代碼中的普通表,不能做爲userdata的metatable。必須使用luaL_newmetatable建立的表才能做爲userdata的metatable。

在openlib函數中,添加一個userdata 的 metatable表,

int OnOpenlib( lua_State* L )

{

...

luaL_newmetatable( L, 「ObjectMetatable");

}

luaL_newmetatable把新建立的表放在棧頂。

注意:新建立的ObjectMetatable表僅在棧中被聲明,並無加入到lua代碼中。若是在之後的lua代碼中使用ObjectMetatable.__index等操做,會提示ObjectMetatable:a nil value。

步驟2:

這是咱們重寫上面的New方法。

int NewObject( lua_State* L )

{

 luaObject* wrapper = (luaObject*) lua_newuserdata( L, sizeof(luaObject) );

 wrapper->data = new CObject;

 luaL_getmetatable( L, 」ObjectMetatable「);
 lua_setmetatable( L, -2 );

 return 1;
}

這樣咱們就爲新生成的luaObject對象添加metatable。

luaL_getmetatable( L, 」ObjectMetatable「)獲取ObjectMetatable表,並放入棧頂。

lua_setmetatable( L, -2 )則把新生成的userdata的metatable設置爲ObjectMetatable。

步驟3:

value = obj[5]的取下標操做對應的是__index域,而

obj[5]=2;對應的是__newindex域。

因此咱們須要添加ObjectMetatable的__index,__newindex域。

咱們重寫int OnOpenlib( lua_State* L )方法

int OnOpenlib( lua_State* L )

{

...

luaL_newmetatable( L, 「ObjectMetatable");

lua_pushstring( L, "__index" );
 lua_pushcfunction( L, GetValue );
 lua_rawset( L, -3 ); // ObjectMetatable.__index = GetHorizonValue

 lua_pushstring( L, "__newindex" );
 lua_pushcfunction( L, SetValue );

lua_rawset( L, -3 ); // ObjectMetatable.__newindex = GetHorizonValue

}

GetValue 與SetValue 是自定義的C函數,能夠不用被註冊到lua代碼中。

在lua中調用

v=obj[5]

時,會觸發元函數metatable.__index,obj、5會被依次入棧。

因此GetValue方法咱們能夠寫爲

int GetValue(lua_State* L)

{

luaL_checktype(L, -1, LUA_TNUMBER);
 luaL_checktype(L, -2, LUA_TUSERDATA);

 luaObject* wrapper = (luaObject*)   lua_touserdata(L, -2);

 ASSERT( wrapper->data != NULL );
 if ( wrapper->data == NULL )
 {
  lua_pushstring( L, "GetHorizonValue: NULL wrapper " );
  lua_error(L);
  return 1;
 }

 int index = (int)(float)lua_tonumber(L, -1);

 int value = wrapper->data.v[index];

lua_pushnumber( L, value );

return 1;

}

相關文章
相關標籤/搜索