lua和C++相互调用

从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);语句获取栈对象供后续访问。     接下来判断参数是否是数字,如果两个参数都是数字,那么进行加操作,将结果压入栈中,将压入栈中的数据的个数返回。注意,返回值代表压入栈中的元素的个数,而不是某种计算结果或其它意义的返回值。通过改变返回值来查看程序的输出,这样可以对返回值的含义有个感性的了解。

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

要注册类的成员函数,则需要调用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"); 

转载自http://hi.baidu.com/li9chuan/blog/item/e65e1d6dc0bd79f642169461.html

lua和C++相互调用

时间: 2024-10-10 01:16:13

lua和C++相互调用的相关文章

lua编程之lua与C相互调用

lua是扩展性非常良好的语言,虽然核心非常精简,但是用户可以依靠lua库来实现大部分工作.除此之外,lua还可以通过与C函数相互调用来扩展程序功能.在C中嵌入lua脚本既可以让用户在不重新编译代码的情况下修改lua代码更新程序,也可以给用户提供一个自由定制的接口,这种方法遵循了机制与策略分离的原则.在lua中调用C函数可以提高程序的运行效率.lua与C的相互调用在工程中相当实用,本文就来讲解lua与C相互调用的方法. Lua与C相互调用的首要问题是如何交换数据,lua API使用了一个抽象的栈与

Cocos2d-x3.0下 Lua与C++相互调用

这里讲下Lua与C++之间如何实现相互调用 原文连接:http://blog.csdn.net/qqmcy/article/details/26052771 DJLCData.h 实现类 // // DJLCData.h // uitestLua // // Created by 杜甲 on 14-5-17. // // #ifndef __uitestLua__DJLCData__ #define __uitestLua__DJLCData__ #include "cocos2d.h"

菜鸟入门之lua与c++相互调用(包含多个demo)

前两篇文章中,已经介绍了使用vs2010编译lua5.1源码生成lua.lib 和 vs项目中使用c++调用lua,可以保证demo在vs上运行起来了.这里再详细介绍下c++和lua之间的相互调用以及原理. c++与lua直接的调用,实际上通过一个栈结构来传递数据,该栈结构栈顶的索引值为-1,向栈底方向索引值依次为-1 ,-2......栈顶索引为1.栈结构里可以放函数,表,字符串,整形等各种lua的基本数据. 一.在当前cpp目录下创建test.lua文件,用于与c++交互调用,代码如下: p

Lua与C++相互调用

{--1.环境--} 为了快速入手,使用了小巧快速的vc++6.0编译器 以及在官网下载了Lua安装包..官网地址{--http://10.21.210.18/seeyon/index.jsp--} 两者都安装好后,即可进行 {--2.工程以及配置--} 1.首先用vc++6.0创建一个简单的win32 console application 2.从Lua的安装目录下复制include和lib两个目录下的文件到刚刚创建的工程的目录下. {include:包含了lua的.h头文件} {lib:包含

uLua学习笔记(三):Unity3D和Lua之间的相互调用

这篇笔记主要集中学习一下uLua和Unity3D之间相互调用的方法,我们导入了uLua之后,现在会弹出一个类似学习屏幕的东西,如下: 先赞一个! Unity3D调用Lua Unity3D调用Lua的方法还是比较简单的,所以先说这个,由于这部分在学习笔记(一)中已经说的挺多的了,更多的内容点击这里回去看,所以这里我们就来看一个简单的示例即可: 1 using LuaInterface; 2 using UnityEngine; 3 4 public class UnityCallLua : Mon

C#与lua相互调用

Lua是一种很好的扩展性语言,Lua解释器被设计成一个很容易嵌入到宿主程序的库.LuaInterface则用于实现Lua和CLR的混合编程. (一)C#调用Lua 测试环境:在VS2015中建一个C#控制台应用程序,并添加LuaInterface.dll的引用 LuaInterface下载地址:http://luaforge.net/projects/luainterface/ (下载luainterface-1.5.3,这里面的资源比较多) LuaInterface.Lua类是CLR访问Lua

C程序与Lua脚本相互调用

Lua脚本是一种可用于C程序开发/测试的工具,本篇介绍一下C程序与Lua脚本如何进行相互调用,更加详细的操作参见<Programing in Lua>.本文分为3个部分:1.Windows环境下Lua的下载以及安装注意事项:2.Visual C++6.0中Lua的配置:3.C程序与Lua脚本相互调用实例. 1.Windows环境下Lua的下载以及安装注意事项 a.下载Lua for Windows,笔者用的版本是V5.1.4-35: b.上微软官网,下载Visual C++运行库——vcred

Lua与C的相互调用

闲的蛋疼,让C和Lua玩包剪锤.结果C以微弱的优势胜出了. 言归正传,这次主要是想练习Lua和C的相互调用. 一.C调用Lua函数 1. luaL_dofile(L, fn); 该函数可以让Lua虚拟栈读取路径为fn的Lua文件,其实质是: lua_loadfile(L, fn) || lua_pcall(L, 0, Lua_MUTIRET, 0) 实际上,lua_loadfile只是把Lua文件加载到VM,成为一个可执行的对象,但却还没有执行它,所以还不能使用. 而lua_pcall则把该Lu

Lua学习笔记6:C++和Lua的相互调用

Lua版本:5.2.3 一 C++ 调用Lua 1 目录结构 CppCallLua { main.cpp script{ test.lua } lualia{ lua.h lualib.h laux.lib.h luaconf.h liblua.a } } 2 代码 //main.cpp #include <iostream> extern "C" { #include "lualib/lua.h" #include "lualib/luali