<--!版权所有foruok,转载注明出处!-->
从lua调用C++函数和对象
利用LuaPlus可以方便的从C++中调用lua脚本,翻过也一样。通过注册函数或类对象,lua便可以访问C++。一、C风格函数注册
Lua提供了C风格的回调函数注册,该函数原型如下:
int
Callback(LuaState
*
state);
int
CStyleAddFunc(LuaState
*
state)
{ LuaStack args(state); if( args[1].IsNumber() && args[2].IsNumber() ) { state->PushNumber(args[1].GetInteger() + args[2].GetInteger()); return 1; } return 0; }
void
TestCFunctionCallBack()
{ LuaStateOwner state; //"print" need this state->OpenLibs(); //register my function CStyleAddFunc to Add state->GetGlobals().Register("Add", CStyleAddFunc); //call my function and print the result state->DoString("ret = Add(1,5); print(ret)"); }
int
_tmain(
int
argc, _TCHAR
*
argv[])
{ TestCFunctionCallBack(); return 0; }
class
CTestCallBack
{ public: int NonVirtualFunc(LuaState *state) { LuaStack args(state); printf("In non-virtual member function. no msg. "); return 0; } int virtual VirtualFunc(LuaState *state) { LuaStack args(state); printf("In virtual member function.msg=%s ", args[1].GetString()); return 0; } }
;
void
TestClassMemberFuncReg()
{ LuaStateOwner state; //"print" need this state->OpenLibs(); LuaObject globalobj = state->GetGlobals(); CTestCallBack tcb; 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; } //const is necessary virtual void SeeMessage(const char *msg) { printf("msg=%s ", msg); } }
;
void
TestRegisterDirect()
{ LuaStateOwner state; state->OpenLibs(); LuaObject gobj = state->GetGlobals(); //register global function directly gobj.RegisterDirect("Add", Add); state->DoString("print(Add(1.5, 2.3))"); //register memberfunction CForRegDirect forobj; gobj.RegisterDirect("MemberSum", forobj, CForRegDirect::Sum); state->DoString("print(MemberSum(1,2,7))"); gobj.RegisterDirect("VirCMsg", forobj, CForRegDirect::SeeMessage); state->DoString("print(VirCMsg('haha,Do you see me?'))"); }
三、注册函子对象
上面两节的方式可以实现简单的回调注册,注册类的成员函数时需要显式提供类指针,不适合用于映射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()
{ LuaStateOwner state; state->OpenLibs(); //create metaTable LuaObject metaTableObj = state->GetGlobals().CreateTable("MultiObjectMetaTable"); metaTableObj.SetObject("__index", metaTableObj); //register functor for multiobject metaTableObj.RegisterObjectFunctor("Print", CMultiObject::Print); //get a instances of CMultiObject CMultiObject obj1(10); //"clone" a object in lua, the lua object(here is table) has obj1's data LuaObject obj1Obj = state->BoxPointer(&obj1); //set lua object's metatable to MetaTableObj obj1Obj.SetMetaTable(metaTableObj); //put lua object to Global scope, thus it can be accessed later. state->GetGlobals().SetObject("obj1", obj1Obj); CMultiObject obj2(20); LuaObject obj2Obj = state->BoxPointer(&obj2); obj2Obj.SetMetaTable(metaTableObj); state->GetGlobals().SetObject("obj2", obj2Obj); //now call Print and Print2 state->DoString("obj1:Print();"); state->DoString("obj2:Print();"); }
LuaObject table1Obj
=
state
->
GetGlobals().CreateTable(
"
table1
"
); table1Obj.SetLightUserData(
"
__object
"
,
&
obj1); table1Obj.SetMetaTable(metaTableObj); LuaObject table2Obj
=
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
"
);