LuaPlus 是 Lua 5.1 的 C++ 增強封裝,提供型別安全的 API、自動棧管理、類別綁定與模組系統,大幅降低嵌入 Lua 的複雜度。本文系統介紹核心功能、進階綁定技巧與自製 Helper 封裝。
| 特性 | 官方 Lua C API | LuaPlus |
| 棧管理 | 手動 lua_push*/lua_pop | RAII 自動管理 |
| 型別安全 | 無 (整數索引) | 模板強型別 LuaObject |
| 錯誤處理 | lua_pcall + 手動檢查 | C++ 例外自動轉換 |
| 類別綁定 | 需手寫 metatable | LuaClass<T> 一鍵綁定 |
| 模組系統 | 手動建表註冊 | LuaModule 封裝 |
基礎操作:執行腳本與變數互通
#include <LuaPlus.h>
using namespace LuaPlus;
LuaStateOwner state; // RAII 管理 lua_State*
// 執行字串/檔案
state->DoString("print('Hello from Lua')");
state->DoFile("scripts/main.lua");
state->DoFile("scripts/compiled.luac"); // 位元碼檔案
// C++ → Lua 設定全域變數
state->GetGlobals().SetNumber("config_max_players", 64);
state->GetGlobals().SetString("server_name", "MyGameServer");
state->GetGlobals().SetBoolean("debug_mode", true);
// Lua → C++ 讀取全域變數
int maxPlayers = state->GetGlobal("config_max_players").GetInteger();
std::string name = state->GetGlobal("server_name").GetString();
bool debug = state->GetGlobal("debug_mode").GetBoolean();
函式雙向呼叫
// C++ 函式註冊給 Lua
int Add(int a, int b) { return a + b; }
state->GetGlobals().RegisterDirect("Add", Add);
// 成員函式註冊
struct Calculator { int Mul(int a, int b) { return a * b; } };
Calculator calc;
state->GetGlobals().RegisterDirect("Mul", calc, &Calculator::Mul);
// Lua 調用 C++
state->DoString("print('3+4=', Add(3,4))"); // 輸出 7
state->DoString("print('3*4=', Mul(3,4))"); // 輸出 12
// C++ 調用 Lua 函式
LuaFunction<int> luaPrint = state->GetGlobal("print");
luaPrint("Called from C++"); // 型別安全調用
C++ 類別完整綁定 (含建構/解構/屬性/多載)
class Logger {
public:
Logger() { printf("Logger() @%p\n", this); }
Logger(int level) : logLevel(level) { printf("Logger(%d) @%p\n", level, this); }
Logger(const Logger* other) : logLevel(other->logLevel) { printf("Logger(copy) @%p\n", this); }
~Logger() { printf("~Logger() @%p\n", this); }
void Log(const char* msg) { printf("[LV%d] %s\n", logLevel, msg); }
void SetLevel(int lv) { logLevel = lv; }
int GetLevel() const { return logLevel; }
private:
int logLevel = 0;
};
// LuaPlusHelper.h 簡化綁定 (需自行實作或下載)
LuaClass<Logger>(state)
.create("Logger") // 預設建構函式
.create<int>("Logger") // 多載:Logger(int)
.create<const Logger*>("Logger") // 複製建構
.destroy("Release") // 顯式釋放
.destroy("__gc") // GC 自動回收
.def("Log", &Logger::Log)
.def("SetLevel", &Logger::SetLevel)
.def("GetLevel", &Logger::GetLevel)
.property("Level", &Logger::GetLevel, &Logger::SetLevel); // 屬性語法糖
Lua 端使用綁定類別
state->DoString(R"(
-- 1. 預設建構
local l1 = Logger()
l1:Log("Hello from default constructor")
l1:Release()
-- 2. 多載建構
local l2 = Logger(3)
l2:Log("Level 3 logger")
l2.Level = 5 -- 屬性寫入
print("Current level:", l2.Level) -- 屬性讀取
-- 3. 複製建構
local l3 = Logger(l2)
l3:Log("Copied from l2")
-- 4. GC 自動回收 (無需手動 Release)
local l4 = Logger(1)
l4:Log("Will be GC'ed")
l4 = nil
collectgarbage()
)";
模組系統:將 C++ 函式群組織為 Lua 模組
LuaModule(state, "GameMath")
.def("Add", Add)
.def("Mul", calc, &Calculator::Mul)
.def("Random", []() { return rand(); }); // Lambda 支援
state->DoString(R"(
print("GameMath.Add(10,20) =", GameMath.Add(10,20))
print("GameMath.Random() =", GameMath.Random())
)");
Table 操作與遍歷
// 建立 Table
LuaObject table = state->GetGlobals().CreateTable("Config");
table.SetInteger("max_players", 100);
table.SetNumber("gravity", 9.81);
table.SetString("map_name", "Dust2");
table.SetWideString("welcome", L"歡迎來到伺服器");
table.SetInteger(1, "FirstElement"); // 陣列部分
// 巢狀 Table
state->GetGlobals().CreateTable("Nested")
.SetObject("config_ref", table) // 參考同一 Table
.SetString("config_copy", "independent");
// 讀取與遍歷
LuaObject cfg = state->GetGlobals()["Config"];
int maxP = cfg.GetByName("max_players").GetInteger();
for (LuaTableIterator it(cfg); it; it.Next()) {
std::string key = it.GetKey().GetString();
LuaObject val = it.GetValue();
// 處理 key-value...
}
進階主題:錯誤處理與效能優化
- 例外安全:LuaPlus 將 Lua 錯誤轉為
LuaException,建議 try-catch 包裹 DoString/DoFile。
- 虛擬函式限制:
LuaClass 不支援虛擬函式綁定,需以非虛擬介面模式 (NVI) 封裝。
- 成員變數存取:不支援直接綁定資料成員,需透過 Getter/Setter。
- 輕量級替代:sol2 (Header-only, C++17, 更現代)、Luabind (Boost 依賴, 功能豐富)。
資源下載
- LuaPlus 官方:luaplus.org (SVN:
svn://svn.luaplus.org/LuaPlus/work51)
- LuaPlusHelper 封裝:下載連結
- 測試專案 (VS2008):下載連結
- 上一篇文章: GB2312 漢字筆畫數查表完整資料 (第一部份:B0-D5 區)
- 下一篇文章: C++ 嵌入 Python 實戰:原生 API 與 Boost.Python 兩種方案對比
Copyright ©
程式碼之家 All Rights Reserved