日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

tolua++初探(六)

系統 1934 0
這是學習tolua++的最后一篇了。在這一篇里完成一個稍微復雜一點的例子(^_^其實還是很簡單)。 導出三個類CBase、CDerived1、CDerived2到lua,導出兩個函數toDerived1、toDerived2。lua腳本中聲明兩個函數Derived1Test和Derived2Test,我們在C++中調用。Derived1Test和Derived2Test會調用toDerived*對其參數進行向下轉換(從CBase轉到CDerived*),然后調用派生類的方法做一些測試。 基本上和前面幾個例子類似,新增加的部分是在C++中調用Lua腳本里定義的函數。這牽涉到虛擬棧的操作,后面會解釋一下。 還是老樣子,先把實際的頭文件列出來。tlclass.h如下:
#ifndef__TOLUACLASS_h #define __TOLUACLASS_h class CBase ... { public : CBase() ... {} virtual ~ CBase() ... {} virtual void ShowMessage() ... {printf( " BaseClass " );} static char * ClassName() ... { return " CBase " ;} } ; class CDerived1: public CBase ... { public : CDerived1() ... {} ~ CDerived1() ... {} void ShowMessage() ... {printf( " Derived1Class " );} void ShowDerived1() ... {printf( " showderived11111 " );} } ; class CDerived2: public CBase ... { public : CDerived2() ... {m_nNumber = 0 ;} ~ CDerived2() ... {} void ShowMessage() ... {printf( " Derived2Class " );} void ShowDerived2() ... {printf( " showderived22222 " );} void SetNumber( int num) ... {m_nNumber = num;} int GetNumber() ... { return m_nNumber;} protected : int m_nNumber; } ; extern CDerived1 * toDerived1( void * p); extern CDerived2 * toDerived2( void * p); #endif
tlclass.pkg如下:
$#include " tlclass.h " class CBase ... { public : virtual void ShowMessage(); static char * ClassName(); } ; class CDerived1: public CBase ... { public : void ShowMessage(); void ShowDerived1(); } ; class CDerived2: public CBase ... { public : void ShowMessage(); void ShowDerived2(); void SetNumber( int num); int GetNumber(); } ; CDerived1 * toDerived1( void * p); CDerived2 * toDerived2( void * p);
這次多定義了兩個函數toDerived1和toDerived2,全局的。我們也可以把他們直接放在類中,或者一個MODULE中。module大概是類似的namespace的東西,把一堆雜七雜八的家什如變量、常量、函數、類實例等放在一起,在lua中通過"."來訪問。下面是手冊中的例子:
modulemod ... { #define N extern int var; int func(...): }
這樣我們可以在lua中用mod.N,mod.var,mod.func來訪問其成員。 原本toDerived*的參數是CBase*,但是從C++向Lua函數傳參數的時候我調用了lua_pushlightuserdata,結果在腳本中報錯,說toDerived*應當接受CBase*而非userdata。于是干脆把參數修改成void*,這下lua不再叫喚了。 好了,到了列出驅動文件的時候了。CallLuaFunc.cpp:
#include " lua.hpp " #include " tlclass.h " CDerived1 * toDerived1( void * p) ... { return dynamic_cast < CDerived1 *> ((CBase * )p); } CDerived2 * toDerived2( void * p) ... { return dynamic_cast < CDerived2 *> ((CBase * )p); } int tolua_calllua_open(lua_State * ); int _tmain( int argc,_TCHAR * argv[]) ... { lua_State * L = luaL_newstate(); luaopen_base(L); tolua_calllua_open(L); luaL_dofile(L, " ../scripts/CallLuaFunc.lua " ); // callluafunction CBase * p1 = new CDerived1(); CBase * p2 = new CDerived2(); // callDerived1Test lua_getglobal(L, " Derived1Test " ); lua_pushlightuserdata(L,p1); if (lua_pcall(L, 1 , 0 , 0 ) != 0 ) ... { fprintf(stderr, " callDerived1Testfailed:%s " ,lua_tostring(L, - 1 )); } // callDerived2Test lua_getglobal(L, " Derived2Test " ); lua_pushlightuserdata(L,p2); if (lua_pcall(L, 1 , 0 , 0 ) != 0 ) ... { fprintf(stderr, " callDerived2Testfailed:%s " ,lua_tostring(L, - 1 )); } printf( " ThisinfoisprintinC++! CDerived2.GetNumber()=%d " ,((CDerived2 * )p2) -> GetNumber()); deletep1; deletep2; lua_close(L); return 0 ; }
這次驅動文件有了點新的變化:1)兩個全局導出函數;2)調用lua函數的代碼。分開來看。 導出函數toDerived*很簡單,只是調用dynamic_cast來向下轉換而已。如果轉換失敗,dynamic_cast會返回null。當我們要從基類指針轉換到派生類指針時,最好用dynamci_cast,直接強制轉換是危險的,除非你明確的知道某個指針指向的對象是什么。 在C++中調用lua腳本的函數大概分為三步: a..找到函數并入棧;(這里是 lua_getglobal(L, " Derived1Test " );) b..參數入棧;(這里是 lua_pushlightuserdata(L,p1);) c..調用lua_pcall進行實際調用 第一步不必說了;第二步可以傳遞任意個任意類型的參數,lua_pushnumber,lua_pushstring,lua_pushboolean等等可以調用;第三步是調用lua_pcall,lua_pcall第一個參數是lua_State*,這是我們的工作環境了。第二參數是要傳遞的參數個數,我們這里是1;第三個參數是lua函數返回的結果個數,我們的lua函數不返回結果,設為0。第四個參數是比較復雜,為0時指lua_pcall會在調用失敗時把原始錯誤信息放到棧上;其它值代表棧的索引,該索引處放了一個錯誤處理函數,lua_pcall失敗時會根據這個索引去調用該函數。 調用失敗的時候我只是簡單地打印一條出錯信息,這個錯誤碼放在棧頂,我們用lua_tostring(L,-1)訪問并轉換為字符串。可以修改下驅動代碼,比如把第二次調用傳入p1,這樣就可以看見錯誤信息。 最后我還是在C++代碼中打印了下CDerived2對象的值,以驗證lua和C++中訪問的是同一個對象。 Lua和C++的交互都是通過棧,所以要寫交互部分的代碼就要不停的出棧入棧,煩死個人。不過這也是Lua靈活的地方。牛人啊,頂禮膜拜吧。 有時間要好好研究下《Programming Lua》,CSDN上有中文版的, lua官方網站 上有英文的。雖然這個是針對5.0版本的lua,但絕大部分東西還是有用的。針對5.1.3的第二版已經出了,可惜我在網上沒有找到鏈接,哪位看到分享一下。 下面看看lua文件callluafunc.lua吧:
print( " nowinCallLuaFunc.lua! " ) -- luafunctiontotestCDerived1,CDerived2,they ' llbecalledfromC++ functionDerived1Test(e) d1 = toDerived1(e); if d1then d1:ShowMessage(); d1:ShowDerived1(); else print( " invalidd1(nil)! " ); end end functionDerived2Test(e) d2 = toDerived2(e); if d2then d2:ShowMessage(); d2:ShowDerived2(); d2:SetNumber( 180 ); print(d2:GetNumber()); else print( " invalidd2(nil) " ); end end
lua中定義了函數Derived1Test和Derived2Test。上面的版本已經不會導致出錯信息了,原始的Derived*Test函數如下:
functionDerived1Test(e) d1 = toDerived1(e); d1:ShowMessage(); d1:ShowDerived1(); end functionDerived2Test(e) d2 = toDerived2(e); d2:ShowMessage(); d2:ShowDerived2(); d2:SetNumber( 180 ); print(d2:GetNumber()); end
原始的Derived*Test函數沒有錯誤檢查,所以從C++中用lua_pcall調用時可能會產生錯誤信息。 又想了下,這樣的類型轉換太復雜了,tolua++提供了轉換機制,可以用的。CEGUI用的就是。 tolua++生成了一些工具函數,在tolua為名的module中。其中tolua.cast就是用來做類型轉換的。只需要改動tlclass.pkg文件,加入下面的代碼:
$[ testHelper = ... {} functiontestHelper.toDerived1(e) return tolua.cast(e, " CDerived1 " ) end functiontestHelper.toDerived2(e) return tolua.cast(e, " CDerived2 " ) end $]
$[和$]結合,用來直接插入lua代碼。我生成一個名為testHelper的table,給testHelper添加兩個轉換函數。 重新用tolua++編譯,再編譯工程。就可以在腳本中調用testHelper.toDerived*來轉換了。 下面是更改后的
callluafunc.lua文件:
print( " nowinCallLuaFunc.lua! " ) -- luafunctiontotestCDerived1,CDerived2,they ' llbecalledfromC++ functionDerived1Test(e) d1 = testHelper.toDerived1(e); if d1then d1:ShowMessage(); d1:ShowDerived1(); else print( " invalidd1(nil)! " ); end end functionDerived2Test(e) d2 = testHelper.toDerived2(e); if d2then d2:ShowMessage(); d2:ShowDerived2(); d2:SetNumber( 180 ); print(d2:GetNumber()); else print( " invalidd2(nil) " ); end end
僅僅是將toDerived*調用轉換成了testHelper.toDerived*。運行了一下,結果是正常的。
好啦好啦,就到這里啦。 通過兩天的學習,我已經確定可以在項目中使用tolua++了,它是"AS IS"的,可以用于任何目的。到目前位置所演示的一些特性,可以滿足我的需要。 嗯,有些未完成的東西,比如UNICODE、多線程環境下對lua的調用等,慢慢用到了再說吧。

tolua++初探(六)


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

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

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

【本文對您有幫助就好】

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

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 嘉义县| 平乡县| 湘乡市| 大名县| 商都县| 鱼台县| 黎川县| 安康市| 苗栗县| 龙川县| 容城县| 都匀市| 光山县| 集安市| 商洛市| 静安区| 子长县| 宁化县| 独山县| 循化| 石门县| 巴林左旗| 韩城市| 沙河市| 麻阳| 永安市| 仙游县| 太康县| 九台市| 武陟县| 荆州市| 韶山市| 福州市| 高雄市| 怀柔区| 宣威市| 嫩江县| 旅游| 广宁县| 奎屯市| 会泽县|