tolua總結(三)


Lua與c++互調

上一節我們實現了一個c++的封裝類,通過該類我們就可以調用lua中的函數。可是這還滿足不了我們的需求,我們還想通過lua來調用我們c++的方法。通過研究/tolua++-1.0.93/src/tests下的例子,結合c++的特性,我總結了一個tolua的例子。不能說相當完美,但是基本的功能已經能夠滿足項目的需求了,而且通過這個例子,也可以使各位對tolua的語法以及用法有一個初步的了解。

本例只是一個簡單的lua與c++互調的示例,如果想要更進一步的學習tolua,可以參考/tolua++-1.0.93/src/tests下的例子,那些例子都是相當的經典。

另外鑒於tolua的強大,文章中可能有一些描述不清楚的地方,望大家能夠給予指出,我再給予完善。如有不足之處還望大家給予指正,如有疑問可在評論中指出,我會盡快給予解決。

1    代碼

CToLua.h(參照上一節)

CToLua.cpp(參照上一節)

CArray.h

#ifndef CARRAY_H_
#define CARRAY_H_

struct Point
{
float x;
float y;
};

extern int a[10];
extern Point p[10];
#endif


CArray.cpp

#include "CArray.h"

int a[10] = {1,2,3,4,5,6,7,8,9,10};
Point p[10] = {{0,1},{1,2},{2,3},{3,4},{4,5},{5,6},{6,7},{7,8},{8,9},{9,10}};

 

CBase.h

#ifndef CBASE_H_
#define CBASE_H_

#include <iostream>
#include <string>
using namespace std;

class CBase
{
public:
CBase();
virtual ~CBase();
void dispalyName();
virtual void Print();
protected:
string m_sName;
};

extern CBase* toBase(void* p);

#endif


CBase.cpp

#include "CBase.h"

CBase::CBase()
{
m_sName = "CBase";
}

CBase::~CBase()
{
}

void CBase::dispalyName()
{
cout << m_sName <<endl;
}

void CBase::Print()
{
cout << "I'm CBase" << endl;
}

CBase* toBase(void* p)
{
return (CBase*)p;
}

 

CChildA.h

#ifndef CCHILDA_H_
#define CCHILDA_H_

#include "CBase.h"

class CChildA : public CBase
{
public:
CChildA();
~CChildA();
void Print();
};
#endif


CChildA.cpp

#include "CChildA.h"

CChildA::CChildA()
{
m_sName = "CChildA";
}

CChildA::~CChildA()
{
}

void CChildA::Print()
{
cout << "I'm CChildA" << endl;
}


CChildB.h

#ifndef CCHILDB_H_
#define CCHILDB_H_

#include "CBase.h"

class CChildB : public CBase
{
public:
CChildB();
~CChildB();
void Print();
};
#endif


CChildB.cpp

#include "CChildB.h"

CChildB::CChildB()
{
m_sName = "CChildB";
}

CChildB::~CChildB()
{
}

void CChildB::Print()
{
cout << "I'm CChildB" << endl;
}


CLuaComm.h

#ifndef CLUACOMM_H_
#define CLUACOMM_H_

int tolua_array_open (lua_State*);
int tolua_base_open (lua_State*);
int tolua_childA_open (lua_State*);
int tolua_childB_open (lua_State*);

#endif


mian.cpp

#include "CToLua.h"
#include "CLuaComm.h"
#include "CBase.h"
#include "CChildA.h"
#include "CChildB.h"

int main()
{
CToLua tolua;
tolua_array_open(tolua.getState());
tolua.loadLuaFile("/home/tolua/test/array.lua");

tolua_base_open(tolua.getState());
tolua_childA_open(tolua.getState());
tolua_childB_open(tolua.getState());
tolua.loadLuaFile("/home/tolua/test/test.lua");
double iValue = tolua.callFileFn("add", "%d%f", 20, 3.69); // 23.69
cout << iValue << endl;
iValue = tolua.callFileFn("sub", "%f%i", 23.69,20); // 3.69
cout << iValue << endl;

CBase base;
CChildA childA;
CChildB childB;
tolua.callFileFn("test1", "%z%z%z", &base, &childA, &childB);
tolua.callFileFn("test2","");
return 0;
}


CArray.pkg

$#include "CArray.h"

struct Point
{
float x;
float y;
};

extern int a[10];
extern const Point p[10];

 

CBase.pkg

$#include "CBase.h"

class CBase
{
public:
CBase();
virtual ~CBase();
void dispalyName();
virtual void Print();
};

extern CBase* toBase(void* p);

 

CChildA.pkg

$#include "CChildA.h"

class CChildA : public CBase
{
public:
CChildA();
~CChildA();
void Print();
};

 

CChildB.pkg

$#include "CChildB.h"

class CChildB : public CBase
{
public:
CChildB();
~CChildB();
void Print();
};

 

array.lua

for i=0,9 do
print (a[i])
end

for i=0,9 do
print (p[i].x .. p[i].y)
end

 

test.lua

function add (x,y)
return x+y
end

function sub (x,y)
return x-y
end

function test1 (base,childA,childB)
b = toBase(base)
cA = toBase(childA)
cB = toBase(childB)
b:dispalyName()
cA:dispalyName()
cB:dispalyName()
b:Print()
cA:Print()
cB:Print()
return 1
end

function test2 ()
b = CBase:new()
cA = CChildA:new()
cB = CChildB:new()
b:dispalyName()
cA:dispalyName()
cB:dispalyName()
b:Print()
cA:Print()
cB:Print()
b:delete()
cA:delete()
cB:delete()
end

 

2    命令

tolua++ -n array -o LArray.cpp CArray.pkg

tolua++ -n base -o LBase.cpp CBase.pkg

tolua++ -n childA -o LChildA.cpp CChildA.pkg

tolua++ -n childB -o LChildB.cpp CChildB.pkg

這些命令的作用在《tolua++安裝》中已經做了解釋,不明白的可以去那里先學習一下。

3    編譯&運行

因為我用的eclipse進行的開發,eclipse自動為我生成了makefile,所以此處就不費事去寫makefile了,如果不喜歡使用eclipse的,可以使用如下這個偷懶的編譯方式:

g++ -o test *.cpp -ltolua++

運行結果:

1

2

3

4

5

6

7

8

9

10

01

12

23

34

45

56

67

78

89

910

23.69

3.69

// 以下為test1的結果

CBase

CChildA

CChildB

I'm CBase

I'm CChildA

I'm CChildB

// 以下為test2的結果

CBase

CChildA

CChildB

I'm CBase

I'm CChildA

I'm CChildB

4    解說

這個例子包含了全局函數、數組、繼承、多態。不僅支持c++傳自定義的對象到lua中,也支持lua調用c++對象的方法。已經基本包含了我們所想要實現的功能。另外tolua還支持枚舉、命名空間、變量等,這些可以參考/tolua++-1.0.93/src/tests下的例子,都很易理解。

CArray.pkg文件。這里邊的$#include "CArray.h"中的$代表其后的內容將原方不動的插入到tolua生成的cpp文件中。

CBase.pkg文件。因為我們通過傳參把CBase*傳入到parseParameter方法,又利用va_arg將指針轉化為void*,再通過lua_pushlightuserdata將指針傳入到lua腳本中。在lua腳本中,我們並不能直接使用這個void*的指針去操作,而需要將該指針再轉化為CBase*,所以我們添加了extern CBase* toBase(void* p);方法,用來將void*轉化為CBase*。這樣我們在lua腳本中只需要先調用toBase方法將void*轉化為CBase*然后賦值給一個變量,就可以通過這個變量操作該CBase*實際指向的對象的方法了,這里就體現出多態的特性啦。

如果我們在pkg文件中,也對類得構造和析構做了定義,那么在lua文件中,構造函數將映射為new(),而析構函數將映射為delete()。C++中new的對象將由c++去釋放,而在lua中生成的對象將由lua釋放。

在main函數中,我們在調用loadLuaFile方法前,需要先調用tolua生成的cpp中的int tolua_*_open(lua_State*)方法。我們將所有open方法的聲明都添加到CLuaComm.h中。

tolua.callFileFn("test1", "%z%z%z", &base, &childA, &childB);方法是將我們生成的類傳入到lua腳本中執行。

tolua.callFileFn("test2","");是直接調用lua腳本中的test2方法,該方法沒有參數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM