去年我作了一個Lua腳本的C++包裝,有許多朋友感興趣,并嘗試使用,我感到受寵若驚。事實上,我作的包裝,學(xué)習(xí)的目的比較強(qiáng),它還是有許多缺陷的。為了讓朋友們少走彎路,我推薦使用LuaPlus作為C++的包裝。
LuaPlus是Lua的C++增強(qiáng),也就是說,LuaPlus本身就是在Lua的源碼上進(jìn)行增強(qiáng)得來的。用它與C++進(jìn)行合作,是比較好的一個選擇。
LuaPlus目前版本為:LuaPlus for Lua 5.01 Distribution Build 1080 (February 28, 2004)。大家可以到http://luaplus.org/ 站點下載:
源碼?? (http://wwhiz.com/LuaPlus/LuaPlus50_Build1081.zip)
目標(biāo)碼 (http://wwhiz.com/LuaPlus/LuaPlus50_Build1081_Win32Binaries.zip)
我將在下面說明,如何使用LuaPlus,以及如何更方便的讓LuaPlus與C++的類合作無間。
1. 調(diào)用Lua腳本
??? // 創(chuàng)建Lua解釋器:
??? LuaStateOwner state;
???
??? // 執(zhí)行Lua腳本:
??? state->DoString("print('Hello World\n')");
??? // 載入Lua腳本文件并執(zhí)行:
??? state->DoFile("C:\\test.lua");
??? // 載入編譯后的Lua腳本文件并執(zhí)行:
??? state->DoFile("C:\\test.luac");
2. 與Lua腳本互相調(diào)用
??? // 為Lua腳本設(shè)置變量
??? state->GetGlobals().SetNumber("myvalue", 123456);
??? // 獲得Lua變量的值
??? int myvalue = state->GetGlobal("myvalue").GetInteger();
???
??? // 調(diào)用Lua函數(shù)
??? LuaFunction<int> luaPrint = state->GetGlobal("print");
??? luaPrint("Hello World\n");
???
??? // 讓Lua調(diào)用C語言函數(shù)
??? int add(int a, int b){ return a+b;}
??? state->GetGlobals().RegisterDirect("add", add);
??? state->DoString("print(add(3,4))");
???
??? // 讓Lua調(diào)用C++類成員函數(shù)
??? class Test{public: int add(int a, int b){return a+b;}};
??? Test test;
??? state->GetGlobals().RegisterDirect("add", test, add);
??? state->DoString("print(add(3,4))");
???
3. 在Lua腳本中使用C++類
???
??? 這個稍微有點小麻煩。不過,我包裝了一個LuaPlusHelper.h的文件,它可以很輕松的完成這個工作。它的實現(xiàn)也很簡單,大家可以從源碼上來獲得如何用純LuaPlus實現(xiàn)同樣的功能。
??? 不過,這里仍然有一個限制沒有解決:不能使用虛成員函數(shù)。不過考慮到我們僅是在Lua調(diào)用一下C++函數(shù),并不是要將C++完美的導(dǎo)入到Lua,這個限制完全可以接受。
??? 另外,類成員變量不能直接在Lua中訪問,可以通過類成員函數(shù)來訪問(比如SetValue/GetValue之類)。
?// 下面是一個簡單的C++類:???
?class Logger
?{
?public:
??void LOGMEMBER(const char* message)
??{
???printf("In member function: %s\n", message);
??}
?
??Logger()
??{
???printf("Constructing(%p)...\n", this);
???v = 10;
??}
??virtual ~Logger()
??{
???printf("Destructing(%p)...\n", this);
??}
?
??Logger(int n)
??{
???printf(" -- Constructing[%d](%p)...\n", n, this);
??}
??Logger(Logger* logger)
??{
???printf(" -- Constructing[%p](%p)...\n", logger, this);
???logger->LOGMEMBER(" Call From Constructor\n");
??}
??int SetValue(int val)
??{
???v = val;
??}
??int GetValue()
??{
???return v;
??}
?public:
??int v;
?};
??? // 導(dǎo)入到Lua腳本:
??? LuaClass<Logger>(state)
?.create("Logger")?// 定義構(gòu)造函數(shù) Logger::Logger()
?.create<int>("Logger2")??// 定義構(gòu)造函數(shù) Logger::Logger(int)
?.create<Logger*>("Logger3")?// 定義構(gòu)造函數(shù) Logger::Logger(Logger*)
?.destroy("Free")??// 定義析構(gòu)函數(shù) Logger::~Logger()
?.destroy("__gc")??// 定義析構(gòu)函數(shù) Logger::~Logger()
?.def("lm", &Logger::LOGMEMBER)? // 定義成員函數(shù) Logger::LOGMEMBER(const char*)
?.def("SetValue", &Logger::SetValue)
?.def("GetValue", &Logger::GetValue);
?
??? // 在Lua中使用Logger類(1):
??? state->DoString(
??????? "l = Logger();"??// 調(diào)用構(gòu)造函數(shù) Logger::Logger()
??????? "l.lm('Hello World 1');"? // 調(diào)用成員函數(shù) Logger::LOGMEMBER(const char*)
??????? "l.Free();"??// 調(diào)用析構(gòu)函數(shù) Logger::~Logger()
??????? );
??? // 在Lua中使用Logger類(2):
??? state->DoString(
??????? "m = Logger(10);"?// 調(diào)用構(gòu)造函數(shù) Logger::Logger(int)
??????? "m.lm('Hello World 2');"? // 調(diào)用成員函數(shù) Logger::LOGMEMBER(const char*)
??????? "n = Logger(m);"?// 調(diào)用構(gòu)造函數(shù) Logger::Logger(Logger*)
??????? "n.lm('Hello World 3');"? // 調(diào)用成員函數(shù) Logger::LOGMEMBER(const char*)
??????? "m.SetValue(11);"
??????? "print(m.GetValue());"
??????? "m,n = nil, nil;"?// m,n 將由Lua的垃極回收來調(diào)用析構(gòu)函數(shù)
??????? );
4. 將一組C函數(shù)歸類到Lua模塊
??? //同上面一樣,我采用LuaPlusHelper.h來簡化:
??? LuaModule(state, "mymodule")
?.def("add", add)
?.def("add2", test, add);
?
??? state->DoString(
??????? "print(mymodule.add(3,4));"
??????? "print(mymodule.add2(3,4));"
??????? );
5. 使用Lua的Table數(shù)據(jù)類型
??? // 在Lua中創(chuàng)建Table
??? LuaObject table = state->GetGlobals().CreateTable("mytable");
??? table.SetInteger("m", 10);
??? table.SetNumber("f", 1.99);
??? table.SetString("s", "Hello World");
??? table.SetWString("ch", L"你好");
??? table.SetString(1, "What");
???
??? // 相當(dāng)于Lua中的:
??? // mytable = {m=10, f=1.99, s="Hello World", ch=L"你好", "What"}
???
??? // 也可以使用table作為key和value:
??? state->GetGlobals().CreateTable("nexttable")
??????? .SetString(table, "Hello")
??????? .SetObject("obj", table);
??? // 相當(dāng)于Lua中的:
??? // nexttable = {mytable="Hello", obj=mytable}
???
??? //獲得Table的內(nèi)容:
??? LuaObject t2 = state->GetGlobals("mytable");
??? int m = t2.GetByName("m").GetInteger();
???
??? LuaObject t3 = state->GetGlobals("nexttable");
??? std::string str = t3.GetByObject(t2).GetString();
???
6? 遍歷Table
?LuaStateOwner state;
?state.DoString( "MyTable = { Hi = 5, Hello = 10, Yo = 6 }" );
?
?LuaObject obj = state.GetGlobals()[ "MyTable" ];
?for ( LuaTableIterator it( obj ); it; it.Next() )
?{
???? const char* key = it.GetKey().GetString();
???? int num = it.GetValue().GetInteger();
?}
篇尾
上面我只是簡單的舉一些例子來說明LuaPlus以及LuaPlusHelper的使用方法,具體文檔請參見LuaPlus。
需要下載LuaPlusHelper,請點這里:
http://www.d2-life.com/LBS/attachments/month_200509/06_zwo3LuaPlusHelper.zip