從lua調用C++函數和對象利用LuaPlus可以方便的從C++中調用lua腳本,翻過也一樣。通過注冊函數或類對象,lua便可以訪問C++。一、C風格函數注冊Lua提供了C風格的回調函數注冊,該函數原型如下:intCallback(LuaState*state);無論是全局函數、類非虛函數、類虛函數,只要符合上面的原型,都可以向Lua注冊。我們以全局函數為例,下面是我們提供的一個回調函數CStyleAddF" />

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

LuaPlus學習(三)

系統 1921 0

<--!版權所有foruok,轉載注明出處!-->

從lua調用C++函數和對象

利用LuaPlus可以方便的從C++中調用lua腳本,翻過也一樣。通過注冊函數或類對象,lua便可以訪問C++。

一、C風格函數注冊

Lua提供了C風格的回調函數注冊,該函數原型如下:
int Callback(LuaState * state);
無論是全局函數、類非虛函數、類虛函數,只要符合上面的原型,都可以向Lua注冊。我們以全局函數為例,下面是我們提供的一個回調函數CStyleAddFunc:
int CStyleAddFunc(LuaState * state) ... { LuaStackargs(state); if (args[ 1 ].IsNumber() && args[ 2 ].IsNumber()) ... { state -> PushNumber(args[ 1 ].GetInteger() + args[ 2 ].GetInteger()); return 1 ; } return 0 ; }
在回調函數中,我們通過棧來訪問參數,棧中可以存貯多個參數, LuaStackargs(state);語句獲取棧對象供后續訪問。 接下來判斷參數是否是數字,如果兩個參數都是數字,那么進行加操作,將結果壓入棧中,將壓入棧中的數據的個數返回。注意,返回值代表壓入棧中的元素的個數,而不是某種計算結果或其它意義的返回值。通過改變返回值來查看程序的輸出,這樣可以對返回值的含義有個感性的了解。 要注冊回到只需調用Register函數即可,這在第一篇中已經用到。下面是測試函數:
void TestCFunctionCallBack() ... { LuaStateOwnerstate; // "print"needthis state -> OpenLibs(); // registermyfunctionCStyleAddFunctoAdd state -> GetGlobals().Register( " Add " ,CStyleAddFunc); // callmyfunctionandprinttheresult state -> DoString( " ret=Add(1,5);print(ret) " ); }
state -> DoString( " ret=Add(1,5);print(ret) " );該句用來從執行Lua命令串。我們先調用Add并將結果賦值給ret變量,然后打印ret的值。 main函數如下:
int _tmain( int argc,_TCHAR * argv[]) ... { TestCFunctionCallBack(); return 0 ; }
編譯運行,一切OK。 我們也可以從Lua腳本文件中調用注冊的回調函數, 第一篇 中有演示。 要注冊類的成員函數,則需要調用Register的另一種形式
Register( const char* funcName, const Callee& callee, int (Callee::*func)(LuaState*), int nupvalues = 0 ); ,提供類實例指針和函數即可完成注冊。下面是示例代碼:
class CTestCallBack ... { public : int NonVirtualFunc(LuaState * state) ... { LuaStackargs(state); printf( " Innon-virtualmemberfunction.nomsg. " ); return 0 ; } int virtual VirtualFunc(LuaState * state) ... { LuaStackargs(state); printf( " Invirtualmemberfunction.msg=%s " ,args[ 1 ].GetString()); return 0 ; } } ; void TestClassMemberFuncReg() ... { LuaStateOwnerstate; // "print"needthis state -> OpenLibs(); LuaObjectglobalobj = state -> GetGlobals(); CTestCallBacktcb; globalobj.Register( " MemberFunc " ,tcb, & CTestCallBack::NonVirtualFunc); state -> DoString( " MemberFunc() " ); globalobj.Register( " VirMemberFunc " ,tcb, & CTestCallBack::VirtualFunc); state -> DoString( " VirMemberFunc('Hi,myboy') " ); }
修改一下main函數,將
TestClassMemberFuncReg()加進去就可以看效果了。

二、任意形式C++函數注冊

LuaPlus提供了 RegisterDirect() 來直接注冊任意形式的函數,這樣更為直接,不必受限于上述的函數原型,使用起來很方便。同樣此函數像Register一樣,可以注冊類的成員函數(也需要顯示指定this指針)。下面是代碼:
float Add( float num1, float num2) ... { return num1 + num2; } class CForRegDirect ... { public : int Sum( int a, int b, int c) ... { return a + b + c; } // constisnecessary virtual void SeeMessage( const char * msg) ... { printf( " msg=%s " ,msg); } } ; void TestRegisterDirect() ... { LuaStateOwnerstate; state -> OpenLibs(); LuaObjectgobj = state -> GetGlobals(); // registerglobalfunctiondirectly gobj.RegisterDirect( " Add " ,Add); state -> DoString( " print(Add(1.5,2.3)) " ); // registermemberfunction CForRegDirectforobj; gobj.RegisterDirect( " MemberSum " ,forobj,CForRegDirect::Sum); state -> DoString( " print(MemberSum(1,2,7)) " ); gobj.RegisterDirect( " VirCMsg " ,forobj,CForRegDirect::SeeMessage); state -> DoString( " print(VirCMsg('haha,Doyouseeme?')) " ); }

三、注冊函子對象

上面兩節的方式可以實現簡單的回調注冊,注冊類的成員函數時需要顯式提供類指針,不適合用于映射C++中的類結構。 RegisterObjectFunctor()和元表(metatable)結合,提供了一種新的方法 。我們不需要在注冊函數時顯式的提供this指針,作為替代,this指針可以從調用者的userdata或__object成員獲取。 元表(metatable)是一個普通的表對象,它定義了一些可以被重寫的操作,如add,sub,mul,index,call等,這些操作以"__"開頭,如__add,__index等。加入你重寫了__add,那么在執行add操作時就會調用你自己定義的__add操作。這種特性可以用來模擬C++中的類對象,注冊函子對象正是利用了這種特性來實現的。 下面我們將一個C++類映射到Lua中。類代碼如下:
class CMultiObject ... { public : CMultiObject( int num):m_num(num) ... { } int Print(LuaState * state) ... { printf( " %d " ,m_num); return 0 ; } protected : int m_num; } ; void TestRegObjectDispatchFunctor() ... { LuaStateOwnerstate; state -> OpenLibs(); // createmetaTable LuaObjectmetaTableObj = state -> GetGlobals().CreateTable( " MultiObjectMetaTable " ); metaTableObj.SetObject( " __index " ,metaTableObj); // registerfunctorformultiobject metaTableObj.RegisterObjectFunctor( " Print " ,CMultiObject::Print); // getainstancesofCMultiObject CMultiObjectobj1( 10 ); // "clone"aobjectinlua,theluaobject(hereistable)hasobj1'sdata LuaObjectobj1Obj = state -> BoxPointer( & obj1); // setluaobject'smetatabletoMetaTableObj obj1Obj.SetMetaTable(metaTableObj); // putluaobjecttoGlobalscope,thusitcanbeaccessedlater. state -> GetGlobals().SetObject( " obj1 " ,obj1Obj); CMultiObjectobj2( 20 ); LuaObjectobj2Obj = state -> BoxPointer( & obj2); obj2Obj.SetMetaTable(metaTableObj); state -> GetGlobals().SetObject( " obj2 " ,obj2Obj); // nowcallPrintandPrint2 state -> DoString( " obj1:Print(); " ); state -> DoString( " obj2:Print(); " ); }
首先我們需要生成一個元表(metatable),將C++類的成員函數注冊到該元表中。然后依據CMultiObject的實例生成lua中與其對應的對象(也是表),將該對象的metatable(也即該表的__object成員)設置為之前產生的元表。最后將新生成的lua對象放置到全局作用域中,這樣后面就可以直接引用這些對象。 我們可以做這樣的近似理解:每個實例的數據元素存放在與已對應的lua table中,而類的成員函數則存放在metatable中(函子對象)。當調用obj1obj:Print()時,會先找到其metatable,然后在metatable中找Print()函數。 這樣便實現了類似C++中的類結構。每個實例有自己的數據,而所有實例共享一份方法列表。 另外一種方式是利用表的userdata來實現,需要先創建一個lua表對象,然后將C++對象obj1設置為該表的userdata(也是設置其__object成員),再將該表對象的metatable設置為我們之前創建的元表。最后就可以用表明來調用Print函數。代碼如下:
LuaObjecttable1Obj = state -> GetGlobals().CreateTable( " table1 " ); table1Obj.SetLightUserData( " __object " , & obj1); table1Obj.SetMetaTable(metaTableObj); LuaObjecttable2Obj = state -> GetGlobals().CreateTable( " table2 " ); table2Obj.SetLightUserData( " __object " , & obj2); table2Obj.SetMetaTable(metaTableObj); state -> DoString( " table1:Print() " ); state -> DoString( " table2:Print() " );
注冊函子對象(RegisterObjectFunctor)這種方式的限制在于:要注冊的函數必須符合原型( int Callback(LuaState * state); )。為了打破這種限制,LuaPlus提供了另外一種方式。

四、直接注冊函子對象

直接注冊函子對象(RegisterObjectDirect)和 RegisterDirect類似,不考慮函數原型,可以直接向元表注冊任意形式的函數 。 為CMultiObject添加新的成員函數:
void Print2( int num) ... { printf( " %d%d /n" ,m_num,num); }
調用RegisterObjectDirect方法:
metaTableObj.RegisterObjectDirect( " Print2 " ,(CMultiObject * ) 0 , & CMultiObject::Print2);
第二個參數 (CMultiObject * ) 0有點奇怪,這是模板參數的需要。 最后:
state -> DoString( " obj1:Print2(5) " ); state -> DoString( " obj2:Print2(15) " ); state -> DoString( " table1:Print2(5) " ); state -> DoString( " table2:Print2(15) " );

五、注銷回調

注銷回調是件簡單的事情,調用SetNil("yourCallBack")即可,如:
gobj.SetNil( " Add " ); metaTableObj.SetNil( " Print2 " );
好了,迄今為止最長的一篇,看著像是LuaPlus文檔的翻譯(?),不過還是加入了一些自己的理解。文檔我看了下,琢磨了半天才明白。希望能快點將LuaPlus用起來。 資料: (1) Lua5.1參考手冊 (2) Lua入門wiki (3)LuaPlus.html,源碼包中帶的。 <--!版權所有foruok,轉載注明出處!-->

LuaPlus學習(三)


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 91福利视频合集 | 亚洲欧美精选 | 国产精品全国探花泡良大师 | 97se亚洲| 久久国产精品久久精 | 欧美色爱综合 | 97久久人人 | 99久久99久久久精品齐齐鬼色 | 精品国产一区二区三区香蕉事 | 日本高清不卡网站免费 | 欧美一级亚洲一级 | 成熟热自由日本语亚洲人 | 久久福利资源网站免费看 | 精品久久久久久18免费看 | 亚洲综合一区二区三区四区 | 成人国产mv免费视频 | 日本中文字幕一区二区高清在线 | 国产成+人+综合+亚洲 欧美 | 欧美日韩在线播放一区二区三区 | 91系列在线 | 看毛片网 | 99精彩视频 | 99热这里只有精 | 性短视频在线观看免费不卡流畅 | 99久久成人 | 久久一卡二卡 | 亚洲人成在线免费观看 | 国产成人精品一区二区 | 久久精品国产99久久 | 北岛玲日韩精品一区二区三区 | 亚洲精品一区二区三区婷婷 | 日本精品一区二区三区在线观看 | 亚洲视频在线观看视频 | 中文精品视频一区二区在线观看 | x99av在线播放| 久久视频精品36线视频在线观看 | 99久久久国产精品免费牛牛四川 | 久久久久久久99精品免费 | 国产日日操 | 四虎国产成人亚洲精品 | 好吊妞免费视频 |