(转)LuaPlus C++ 函数互调

<--!版权所有foruok,转载注明出处!-->

从lua调用C++函数和对象
    利用LuaPlus可以方便的从C++中调用lua脚本,翻过也一样。通过注册函数或类对象,lua便可以访问C++。
   
一、C风格函数注册
    Lua提供了C风格的回调函数注册,该函数原型如下:
    int Callback(LuaState* state);
   
    无论是全局函数、类非虚函数、类虚函数,只要符合上面的原型,都可以向Lua注册。我们以全局函数为例,下面是我们提供的一个回调函数CStyleAddFunc:

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;
}

在回调函数中,我们通过栈来访问参数,栈中可以存贮多个参数,LuaStack args(state);语句获取栈对象供后续访问。     接下来判断参数是否是数字,如果两个参数都是数字,那么进行加操作,将结果压入栈中,将压入栈中的数据的个数返回。注意,返回值代表压入栈中的元素的个数,而不是某种计算结果或其它意义的返回值。通过改变返回值来查看程序的输出,这样可以对返回值的含义有个感性的了解。     要注册回到只需调用Register函数即可,这在第一篇中已经用到。下面是测试函数:

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)");
}
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)
{
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')");
}

修改一下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;
}      //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();");
}

首先我们需要生成一个元表(metatable),将C++类的成员函数注册到该元表中。然后依据CMultiObject的实例生成lua中与其对应的对象(也是表),将该对象的metatable(也即该表的__object成员)设置为之前产生的元表。最后将新生成的lua对象放置到全局作用域中,这样后面就可以直接引用这些对象。     我们可以做这样的近似理解:每个实例的数据元素存放在与已对应的lua table中,而类的成员函数则存放在metatable中(函子对象)。当调用obj1obj:Print()时,会先找到其metatable,然后在metatable中找Print()函数。     这样便实现了类似C++中的类结构。每个实例有自己的数据,而所有实例共享一份方法列表。         另外一种方式是利用表的userdata来实现,需要先创建一个lua表对象,然后将C++对象obj1设置为该表的userdata(也是设置其__object成员),再将该表对象的metatable设置为我们之前创建的元表。最后就可以用表明来调用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()");

注册函子对象(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 C++ 函数互调相关推荐

  1. C++ 和 Java 函数互调

    C++ 和 Java 函数互调 分享经验总结,欢迎加入 项目如下: 知识点: CMakeLists.txt 的使用 c++ 创建子线程,消费者和生产者 ffmpeg 编译 ffmpeg 高低版本库动态 ...

  2. iOS下JS和原生交互,函数互调

    现在越来越多的APP都是H5和原生混合开发,这样确实方便快捷,但是H5的部分总避免不了很多与原生的交互,原生调JS函数还比较简单,原生的API函数stringByEvaluatingJavaScrip ...

  3. cocos2d-x 通过JNI实现c/c++和Android的java层函数互调 .

    转载请注明来自:Alex Zhou的程序世界,本文链接:http://codingnow.cn/cocos2d-x/992.html 本文主要实现两个功能: (1)通过Android sdk的API得 ...

  4. c/c++比较灵活的方法:回调函数和函数指针

    当代码量比较小或者需求固定的时候,可以在一个函数里绑定另一个函数,实现函数互调.但当需要经常改变函数或需要实现动态调用时,绑定的参量就不能实现.这时候需要用到函数指针和函数回调 回调函数:回调函数是一 ...

  5. python函数的命名_python函数命名

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 命名空间的生命周期名称空间的生命周期 内置名称空间:(最长)只要 python解 ...

  6. JSPatch – 动态更新iOS APP

    JSPatch是最近业余做的小项目,只需在项目中引入极小的引擎,就可以使用JavaScript调用任何Objective-C的原生接口,获得脚本语言的能力:动态更新APP,替换项目原生代码修复bug. ...

  7. react- native 入门

    React Native 从入门到源码 React Native 是最近非常火的一个话题,介绍如何利用 React Native 进行开发的文章和书籍多如牛毛,但面向入门水平并介绍它工作原理的文章却寥 ...

  8. 【转】C++/CLI简介(什么是C++/CLI) -------C++/CLI 编程系列一

    要知道C++/CLI是什么,首先知道什么是CLI. 一.CLI简介 CLI:(Common Language Infrastructure,通用语言框架)提供了一套可执行代码和它所运行需要的虚拟执行环 ...

  9. React Native 从入门到原理

    React Native 是最近非常火的一个话题,介绍如何利用 React Native 进行开发的文章和书籍多如牛毛,但面向入门水平并介绍它工作原理的文章却寥寥无几. 本文分为两个部分:上半部分用通 ...

最新文章

  1. 来了解下AbstractList
  2. crontab 时间参数解释
  3. java platform se binary怎么关闭_如何吐槽舌尖上的折磨?diss难吃只会说malo,那还怎么battle?...
  4. 理解三值逻辑与NULL,你离SQL高手更近了一步
  5. [Python] zip() 函数
  6. 智能影视站系统 光线 CMS1.5 正式版
  7. h5 字体加粗_div css布局对文字字体加粗样式设置
  8. 证明题【安于现状还是振翅飞往远方】
  9. hash算法和常见的hash函数
  10. 关于alert(12)与alert(1||2)输出问题解析
  11. Win10笔记本触控板关闭/打开
  12. 海外直播、聊天交友APP的开发及上架GooglePlay体验【Compose版】
  13. 微信小程序的key值
  14. SRS4.0源码分析-SrsRecvThread::cycle
  15. OSC源创会(西安)图文总结
  16. win7下快速启动栏的快捷方式的位置
  17. 未来十年互联网十大发展趋势
  18. android ble mvp,Android mvparms 踩坑
  19. 【Springcloud】<微服务>微服务架构设计理念
  20. Idea 类builder模式插件安装方法

热门文章

  1. pyinstaller安装_如何打包Python Web项目,实现免安装一键启动?
  2. [Vue warn]: Error in mount hook: “TypeError: Cannot read properties of null (reading ‘getAttribute‘)
  3. PCL之点特征直方图(PFH)
  4. wxpython播放视频_使用wxpython显示网络摄像头视频闪烁
  5. 工作问题总结-----付款
  6. 一步步实现windows版ijkplayer系列文章之一Windows10平台编译ffmpeg 4.0.2,生成ffplay
  7. 网站提速-缓存技术(4)
  8. linux源代码剖析之kernel
  9. linux创建新用户及权限
  10. 【李宏毅2020 ML/DL】P11 Logistic Regression | 由逻辑回归中的特征转换巧妙引出“神经网络”的概念