加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

tolua++初探(六)

发布时间:2020-12-14 22:27:36 所属栏目:大数据 来源:网络整理
导读:??? 这是学习tolua++的最后一篇了。在这一篇里完成一个稍微复杂一点的例子(^_^其实还是很简单)。 ??? 导出三个类CBase、CDerived1、CDerived2到lua,导出两个函数toDerived1、toDerived2。lua脚本中声明两个函数Derived1Test和Derived2Test,我们在C++中调
??? 这是学习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()

????

????
void?ShowMessage(){printf("BaseClass );}

????
staticchar*?ClassName(){?returnCBase;?}

????

}
;

?CDerived1?:? public ?CBase

:

????CDerived1()

????
CDerived1()

????

????
?ShowMessage()Derived1Class

????
?ShowDerived1()show?derived22222

}
?CDerived2?:? ?CBase

:

????CDerived2()
{m_nNumber=0;}

????
CDerived2()

????
?ShowMessage()Derived2Class

????
?ShowDerived2()show?derived22222

????
?SetNumber(int?num){?m_nNumber??num;?}

????
??GetNumber()??m_nNumber;?}

protected:

????
?m_nNumber;

}
extern ?CDerived1? * ?toDerived1( void ? ?p);

?CDerived2? ?toDerived2( #endif
??? ??? tlclass.pkg如下:
$#include? " tlclass.h

?CBase

:

????
?ShowMessage();

????
?ClassName();

????

}
?CBase

:

????

????
?ShowDerived1();

}
?CBase

?ShowDerived2();

????
?num);

????
??GetNumber();

????

}
;

CDerived1?
?p);

CDerived2?
?p);
??? 这次多定义了两个函数toDerived1和toDerived2,全局的。我们也可以把他们直接放在类中,或者一个MODULE中。module大概是类似的namespace的东西,把一堆杂七杂八的家什如变量、常量、函数、类实例等放在一起,在lua中通过"."来访问。下面是手册中的例子:
module?mod

{

?
#define?N

?
extern?var;

?
?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?

CDerived1?
?p)

{

????
?dynamic_cast<CDerived1*>((CBase)p);

}

CDerived2?
?p)

CDerived2int ?tolua_calllua_open(lua_State );

?_tmain( ?argc,?_TCHAR ?argv[])

{

????lua_State?
?L??luaL_newstate();

????luaopen_base(L);

????tolua_calllua_open(L);

????luaL_dofile(L,?
../scripts/CallLuaFunc.lua);

????
//call?lua?function

????CBase??p1?new?CDerived1();

????CBase?
?p2??CDerived2();

????
call?Derived1Test????lua_getglobal(L,0);">Derived1Test);

????lua_pushlightuserdata(L,?p1);

????
if(?lua_pcall(L,0);">1,0);">)?!=?)

????
{

????????fprintf(stderr,0);">call?Derived1Test?failed:%s
-));

????}

????
call?Derived2TestDerived2Test

????
?)

????
call?Derived2Test?failed:%s

????printf(
This?info?is?print?in?C++! CDerived2.GetNumber()=%d )p2)->GetNumber());

????delete?p1;

????delete?p2;

????lua_close(L);

????
;

}

??? 这次驱动文件有了点新的变化:1)两个全局导出函数;2)调用lua函数的代码。分开来看。 ??? 导出函数toDerived*很简单,只是调用dynamic_cast来向下转换而已。如果转换失败,dynamic_cast会返回null。当我们要从基类指针转换到派生类指针时,最好用dynamci_cast,直接强制转换是危险的,除非你明确的知道某个指针指向的对象是什么。 ??? 在C++中调用lua脚本的函数大概分为三步: ??? a..找到函数并入栈;(这里是 lua_getglobal(L,0);">);) ??? 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( " now?in?CallLuaFunc.lua! )

-- lua?function?to?test?CDerived1,?CDerived2,?they ' ll?be?called?from?C++

function?Derived1Test(e)?

????d1?
= ?toDerived1(e);

????
if ?d1?then?

????????d1:ShowMessage();?

????????d1:ShowDerived1();?

????
else

????????print(
invalid?d1(nil)! );

????end

end

function?Derived2Test(e)?

????????d2?
?toDerived2(e);?

????
?d2?then

????????d2:ShowMessage();?

????????d2:ShowDerived2();?

????????d2:SetNumber(
180 );

????????print(d2:GetNumber());

????
invalid?d2(nil) );

????end

end
??? lua中定义了函数Derived1Test和Derived2Test。上面的版本已经不会导致出错信息了,原始的Derived*Test函数如下:
?toDerived1(e);

????d1:ShowMessage();?

????d1:ShowDerived1();?

end

function?Derived2Test(e)?

????d2? ?toDerived2(e);?

????d2:ShowMessage();?

????d2:ShowDerived2();?

????d2:SetNumber(
);

????print(d2:GetNumber());

end
??? 原始的Derived*Test函数没有错误检查,所以从C++中用lua_pcall调用时可能会产生错误信息。 ??? 又想了下,这样的类型转换太复杂了,tolua++提供了转换机制,可以用的。CEGUI用的就是。 ??? tolua++生成了一些工具函数,在tolua为名的module中。其中tolua.cast就是用来做类型转换的。只需要改动tlclass.pkg文件,加入下面的代码:

$[

testHelper
= {}

function?testHelper.toDerived1(e)

????
return ?tolua.cast(e,? CDerived1 )

end

function?testHelper.toDerived2(e)

????
CDerived2 )

end

$]

??? $[和$]结合,用来直接插入lua代码。我生成一个名为testHelper的table,给testHelper添加两个转换函数。 ??? 重新用tolua++编译,再编译工程。就可以在脚本中调用testHelper.toDerived*来转换了。 ??? 下面是更改后的
callluafunc.lua文件:
)

function?Derived1Test(e)?

????d1?
?testHelper.toDerived1(e);

????
?d1?then?

????????d1:ShowMessage();?

????????d1:ShowDerived1();?

????

????????print(
);

????end

end

function?Derived2Test(e)?

????????d2?
?testHelper.toDerived2(e);?

????
?d2?then

????????d2:ShowMessage();?

????????d2:ShowDerived2();?

????????d2:SetNumber(
);

????????print(d2:GetNumber());

????
);

????end

end
??? 仅仅是将toDerived*调用转换成了testHelper.toDerived*。运行了一下,结果是正常的。
? ?? ??? 好啦好啦,就到这里啦。 ??? 通过两天的学习,我已经确定可以在项目中使用tolua++了,它是"AS IS"的,可以用于任何目的。到目前位置所演示的一些特性,可以满足我的需要。 ??? 嗯,有些未完成的东西,比如UNICODE、多线程环境下对lua的调用等,慢慢用到了再说吧。 ???

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读