<--!版权所有foruok,转载注明出处!-->
从lua调用C++函数和对象
利用LuaPlus可以方便的从C++中调用lua脚本,翻过也一样。通过注册函数或类对象,lua便可以访问C++。一、C风格函数注册
Lua提供了C风格的回调函数注册,该函数原型如下:
int
Callback(LuaState
*
state);
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
;
}
void
TestCFunctionCallBack()
{
LuaStateOwnerstate;
//
"print"needthis
state
->
OpenLibs();
//
registermyfunctionCStyleAddFunctoAdd
state
->
GetGlobals().Register(
"
Add
"
,CStyleAddFunc);
//
callmyfunctionandprinttheresult
state
->
DoString(
"
ret=Add(1,5);print(ret)
"
);
}
int
_tmain(
int
argc,_TCHAR
*
argv[])
{
TestCFunctionCallBack();
return
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')
"
);
}
二、任意形式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();
"
);
}
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()
"
);
四、直接注册函子对象
直接注册函子对象(RegisterObjectDirect)和
RegisterDirect类似,不考虑函数原型,可以直接向元表注册任意形式的函数
。 为CMultiObject添加新的成员函数:
void
Print2(
int
num)
{
printf(
"
%d%d
/n"
,m_num,num);
}
metaTableObj.RegisterObjectDirect(
"
Print2
"
,(CMultiObject
*
)
0
,
&
CMultiObject::Print2);
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
"
);