序
当前 Lua 的版本已经是 Lua 5.4.3 了。创建工程使用的 Lua 版本是:Lua 5.1.5。
版本比较老,原因比较复杂,因为后续文章使用的 tolua++ 和 luaJIT 对 lua 的支持都停留在 5.1 的版本。
但是不用担心,在此文章使用了一些比较新而且好用的函数,并且将这些函数手动移植到了 Lua 5.1.5 。
VS 2017 中搭建 Lua 5.1
创建静态链接库的空工程、添加lua代码文件。
修改工程配置:


编译工程,生成 lua.lib。
C++ 对原生 Lua 的处理
在封装代码之前,我们先简单的从原生的代码开始。先对 Lua 有个简单的理解。
hello.lua
str = "I am so cool"tbl = {name = "shun", id = 20114442}function add(a,b)return a + b + math.piend
main.cpp
extern "C"{#include "lua.h"#include "lualib.h"#include "lauxlib.h"}// 下面的代码 是处理 原生的 lua脚本的using namespace std;void main(){//1.创建Lua状态lua_State *L = luaL_newstate();if (L == NULL){return;}//2.加载Lua文件int bRet = luaL_loadfile(L, "E:\\hello.lua");if (bRet){cout << "load file error" << endl;return;}//3.运行Lua文件bRet = lua_pcall(L, 0, 0, 0);if (bRet){cout << "pcall error" << endl;return;}//4.读取变量lua_getglobal(L, "str");string str = lua_tostring(L, -1);cout << "str = " << str.c_str() << endl; //str = I am so cool~//5.读取tablelua_getglobal(L, "tbl");lua_getfield(L, -1, "name");str = lua_tostring(L, -1);cout << "tbl:name = " << str.c_str() << endl; //tbl:name = shun//6.读取函数lua_getglobal(L, "add"); // 获取函数,压入栈中lua_pushnumber(L, 10); // 压入第一个参数lua_pushnumber(L, 20); // 压入第二个参数int iRet = lua_pcall(L, 2, 1, 0);// 调用函数,调用完成以后,会将返回值压入栈中,2表示参数个数,1表示返回结果个数。if (iRet) // 调用出错{const char *pErrorMsg = lua_tostring(L, -1);cout << pErrorMsg << endl;lua_close(L);return;}if (lua_isnumber(L, -1)) //取值输出{double fValue = lua_tonumber(L, -1);cout << "Result is " << fValue << endl;}system("pause");//至此,栈中的情况是://=================== 栈顶 ===================// 索引 类型 值// 4 int:30// 3 string:shun// 2 table: tbl// 1 string: I am so cool~//=================== 栈底 ===================//7.关闭statelua_close(L);return;}
使用 C++ 模板封装 Lua
配置 Lua 环境、植入新版本的 Lua 库函数
将 Lua 的头文件和编译的库文件,添加到工程文件中。
我们需要植入一些先版本的 Lua 库函数。因为它们比较好用~ 可以更方便的让 C++ 和 Lua 的相互交互。
创建一个 LuaEx.hpp 文件,包含头文件,并植入函数:
/***************************************************************************************************************************************************vic.MINg 2021/10/11lua 函数扩展,由于使用 lua 版本 5.1.5,一些比较有用的函数 没有,这里将这些函数 扩展到这里,也可以了解 lua 的实现**************************************************************************************************************************************************/#pragma onceextern "C"{#include "lua.h"#include "lualib.h"#include "lauxlib.h"#include "lstate.h"}#define LUAI_UACINT LUA_INTEGERinline const char *luaL_tolstring(lua_State *L, int idx, size_t *len) {if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */if (!lua_isstring(L, -1))luaL_error(L, "'__tostring' must return a string");}else {switch (lua_type(L, idx)) {case LUA_TNUMBER: {// if (lua_isinteger(L, idx))// lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx));// elselua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx));break;}case LUA_TSTRING:lua_pushvalue(L, idx);break;case LUA_TBOOLEAN:lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false"));break;case LUA_TNIL:lua_pushliteral(L, "nil");break;default: {int tt = luaL_getmetafield(L, idx, "__name"); /* try name */const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) :luaL_typename(L, idx);lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx));if (tt != LUA_TNIL)lua_remove(L, -2); /* remove '__name' */break;}}}return lua_tolstring(L, -1, len);}inline void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup){luaL_checkstack(L, nup, "too many upvalues");for (; l->name != NULL; l++) { /* fill the table with given functions */int i;for (i = 0; i < nup; i++) /* copy upvalues to the top */lua_pushvalue(L, -nup);lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */lua_setfield(L, -(nup + 2), l->name);}lua_pop(L, nup); /* remove upvalues */}#define lua_newtable(L) lua_createtable(L, 0, 0)#define luaL_newlibtable(L,l) \lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)#define luaL_newlib(L,l) \(luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX)#ifndef cast#define cast(t, exp) ((t)(exp))#endif#define cast_int(i) cast(int, (i))#define LUA_LOADED_TABLE "_LOADED"struct lua_State;inline int lua_absindex(lua_State *L, int idx) {return (idx > 0 || ispseudo(idx))? idx: cast_int(L->top - L->ci->func) + idx;}inline int luaL_getsubtable(lua_State *L, int idx, const char *fname){lua_getfield(L, idx, fname);lua_pop(L, 1); /* remove previous result */idx = lua_absindex(L, idx);lua_newtable(L);lua_pushvalue(L, -1); /* copy to be left at top */lua_setfield(L, idx, fname); /* assign new table to field */return 0; /* false, because did not find table there */}inline void luaL_requiref(lua_State *L, const char *modname,lua_CFunction openf, int glb) {luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);lua_getfield(L, -1, modname); /* LOADED[modname] */if (!lua_toboolean(L, -1)) { /* package not already loaded? */lua_pop(L, 1); /* remove field */lua_pushcfunction(L, openf);lua_pushstring(L, modname); /* argument to open function */lua_call(L, 1, 1); /* call 'openf' to open module */lua_pushvalue(L, -1); /* make copy of module (call result) */lua_setfield(L, -3, modname); /* LOADED[modname] = module */}lua_remove(L, -2); /* remove LOADED table */if (glb) {lua_pushvalue(L, -1); /* copy of module */lua_setglobal(L, modname); /* _G[modname] = module */}}
模板封装,C++ 调用 Lua 函数
通过封装实现,C++ 调用 Lua 函数。存在 无返回值、一个返回值、多个返回值情况。
LuaHelp.h,面向过程 模板封装。
/*************************************************vic.MINg 2021/10/11使用 模板 对 lua 的封装************************************************/#pragma once#include <iostream>#include <stdexcept>#include <vector>#include "LuaEx.hpp"// 面向过程 封装namespace LuaHelp {union LH_LuaData {bool lh_bool_data;int lh_int_data;double lh_number_data;char* lh_string_data;};enum LH_LuaType {LH_Lua_Bool = 0,LH_Lua_Int,LH_Lua_Number,LH_Lua_String};///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 全局变量 设置inline bool GetGlobal(lua_State* lua_s, const char* g_name){//if (lua_gettop(lua_s) < 1)// return false;lua_getglobal(lua_s, g_name);return true;}inline bool SetGlobal(lua_State* lua_s, const char* g_name){if (lua_gettop(lua_s) < 1)return false;lua_setglobal(lua_s, g_name);return true;}///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 打印 堆 信息inline void PrintStack_Info(lua_State* lua_s,const char* tag = NULL){int lua_size = lua_gettop(lua_s);if (tag)std::cout << "***************************** " << tag << " *****************************" << std::endl;printf("lua_State:0x%x ! \n", lua_s);printf("lua_Size:%d ! \n", lua_size);for (int i = 1; i <= lua_size; i++){printf("[%d](%s):%s\n", i, luaL_typename(lua_s, i), luaL_tolstring(lua_s, i, NULL));lua_pop(lua_s, 1);}}inline void PrintStack_Size(lua_State* lua_s, const char* tag = NULL){int lua_size = lua_gettop(lua_s);if (tag)std::cout << "***************************** " << tag << " *****************************" << std::endl;std::cout << "lua_Size:" << lua_size << std::endl;}///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 特化 LuaChecktemplate<typename _Ty>bool LuaCheck(lua_State* lua_s, int index = -1);/// 检查是否是字符串template<> inline bool LuaCheck<char*>(lua_State* lua_s, int index){return lua_isstring(lua_s, index) == 0 ? false : true;}template<> inline bool LuaCheck<std::string>(lua_State* lua_s, int index){return lua_isstring(lua_s, index) == 0 ? false : true;}/// 检查是否是整数template<> inline bool LuaCheck<int>(lua_State* lua_s, int index){return lua_isnumber(lua_s, index) == 0 ? false : true;}/// 检查是否是浮点数template<> inline bool LuaCheck<double>(lua_State* lua_s, int index){return lua_isnumber(lua_s, index) == 0 ? false : true;}template<> inline bool LuaCheck<float>(lua_State* lua_s, int index){return lua_isnumber(lua_s, index) == 0 ? false : true;}/// 检查是否是布尔值template<> inline bool LuaCheck<bool>(lua_State* lua_s, int index){return lua_isboolean(lua_s, index) == 0 ? false : true;}///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 特化 LuaGettemplate<typename _Ty>_Ty LuaGet(lua_State* lua_s, int index = -1, bool _pop = false); // _pop 表示 是否弹出/// 获取字符串template<> inline char* LuaGet<char*>(lua_State* lua_s, int index, bool _pop){if (!LuaCheck<char*>(lua_s, index)){throw std::logic_error("LuaHelp::LuaCheck<char*> Error!");}char* tmp = (char*)lua_tostring(lua_s, index);if (_pop){lua_remove(lua_s, index);}return tmp;}template<> inline std::string LuaGet<std::string>(lua_State*lua_s, int index, bool _pop){if (!LuaCheck<char*>(lua_s, index)){throw std::logic_error("LuaHelp::LuaCheck<std::string> Error!");}std::string tmpstr = (char*)lua_tostring(lua_s, index);if (_pop){lua_remove(lua_s, index);}return std::move(tmpstr);}/// 获取整型template<> inline int LuaGet<int>(lua_State* lua_s, int index, bool _pop){if (!LuaCheck<int>(lua_s, index)){throw std::logic_error("LuaHelp::LuaCheck<int> Error!");}int tmp = lua_tointeger(lua_s, index);if (_pop){lua_remove(lua_s, index);}return tmp;}/// 获取浮点数template<> inline double LuaGet<double>(lua_State* lua_s, int index, bool _pop){if (!LuaCheck<double>(lua_s, index)){throw std::logic_error("LuaHelp::LuaCheck<double> Error!");}double tmp = lua_tonumber(lua_s, index);if (_pop){lua_remove(lua_s, index);}return tmp;}template<> inline float LuaGet<float>(lua_State*lua_s, int index, bool _pop){if (!LuaCheck<float>(lua_s, index)){throw std::logic_error("LuaHelp::LuaCheck<float> Error!");}float tmp = (float)lua_tonumber(lua_s, index);if (_pop){lua_remove(lua_s, index);}return tmp;}/// 获取布尔值template<> inline bool LuaGet<bool>(lua_State*lua_s, int index, bool _pop){if (!LuaCheck<bool>(lua_s, index)){throw std::logic_error("LuaHelp::LuaCheck<bool> Error!");}bool tmp = (bool)lua_toboolean(lua_s, index);if (_pop){lua_remove(lua_s, index);}return tmp;}///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 特化 LuaPushtemplate<typename _TY>void LuaPush(lua_State* lua_s, _TY);/// 压栈字符串template<> inline void LuaPush<char*>(lua_State* lua_s, char* value){lua_pushstring(lua_s, value);}template<> inline void LuaPush<const char*>(lua_State* lua_s, const char* value){lua_pushstring(lua_s, value);}/// 压栈整型template<> inline void LuaPush<int>(lua_State* lua_s, int value){lua_pushnumber(lua_s, value);}/// 压栈浮点数template<> inline void LuaPush<double>(lua_State* lua_s, double value){lua_pushnumber(lua_s, value);}template<> inline void LuaPush<float>(lua_State* lua_s, float value){lua_pushnumber(lua_s, value);}/// 压栈布尔值template<> inline void LuaPush<bool>(lua_State* lua_s, bool value){lua_pushboolean(lua_s, value);}/// 压栈函数template<> inline void LuaPush<lua_CFunction>(lua_State*lua_g, lua_CFunction fun){lua_pushcfunction(lua_g, fun);}///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 特化 全局变量/// 特化 获取全局变量template<typename _Ty>_Ty LuaGetGlobal(lua_State* lua_s, char*global, bool _pop = true){if (GetGlobal(lua_s, global) == false){throw std::logic_error("LuaHelp::LuaGetGlobal Error!");}_Ty tmp = LuaGet<_Ty>(lua_s, -1, _pop);return tmp;}/// 特化 设置全局变量template<typename _Ty>bool LuaSetGlobal(lua_State* lua_s, char* global, _Ty value){LuaPush<_Ty>(lua_s, value);if (SetGlobal(lua_s, global) == false){throw std::logic_error("LuaHelp::LuaSetGlobal Error!");return false;}return true;}///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 调用 lua 函数模板// __CallLua 压栈 无参数inline void __CallLua(lua_State* lua_g, int& argSize) {}template<typename _FirstArg, typename... _Args>void __CallLua(lua_State* lua_g, int& argSize, _FirstArg arg1, _Args...args) //压入参数{argSize++;LuaPush<_FirstArg>(lua_g, arg1);__CallLua(lua_g, argSize, args...); // 递归 压栈调用}template<typename _Ret, typename... _Args>_Ret CallLuaFuction_return_oneValue(lua_State* lua_g, const char* FunctionName, _Args...args) // 调用lua函数, 一个返回值{if (GetGlobal(lua_g, FunctionName)){int argSize = 0; // 参数个数__CallLua(lua_g, argSize, args...);PrintStack_Info(lua_g, "CallLuaFuction_return_oneValue");if (lua_pcall(lua_g, argSize, 1, 0) != 0){lua_pop(lua_g, 1); // 弹出错误值throw std::logic_error("LuaHelp::CallLuaFuction_return_oneValue Error!");}_Ret value = LuaGet<_Ret>(lua_g);lua_pop(lua_g, 1);return value;}throw std::logic_error("LuaHelp::CallLuaFuction_return_oneValue No Function!");}template< typename... _Args>void CallLuaFuction_return_void(lua_State* lua_g,const char* FunctionName, _Args...args){if (GetGlobal(lua_g, FunctionName)){int argSize = 0; // 参数个数__CallLua(lua_g, argSize, args...);PrintStack_Info(lua_g, "CallLuaFuction_return_void");if (lua_pcall(lua_g, sizeof...(args), 0, 0) != 0){lua_pop(lua_g, 1); // 弹出错误值throw std::logic_error("LuaHelp::CallLuaFuction_return_void Error!");}return;}throw std::logic_error("LuaHelp::CallLuaFuction_return_void No Function!");}template< typename... _Args>void CallLuaFuction_return_multValues(lua_State* lua_g, const char* FunctionName, _Args...args){if (GetGlobal(lua_g, FunctionName)){int argSize = 0; // 参数个数__CallLua(lua_g, argSize, args...);PrintStack_Info(lua_g, "CallLuaFuction_return_multValues");if (lua_pcall(lua_g, sizeof...(args), -1, 0) != 0){lua_pop(lua_g, 1); //弹出错误值throw std::logic_error("LuaHelp::CallLuaFuction_return_multValues Error!");}return;}throw std::logic_error("LuaHelp::CallLuaFuction_return_multValues No Function!");}template< typename... _Args>std::vector<LH_LuaData> GetResult(lua_State* lua_g, _Args...args){int _argsize = sizeof...(args);int argarray[sizeof...(args)] = { args... };std::cout << _argsize << std::endl;std::vector<LH_LuaData> __array = {};int __index = -_argsize + 1;for (int v : argarray){LH_LuaData tmp = { 0 };std::cout << "v:" << v << std::endl;switch (v){case LH_LuaType::LH_Lua_Bool:tmp.lh_bool_data = LuaGet<bool>(lua_g, -1 + __index);break;case LH_LuaType::LH_Lua_Int:tmp.lh_int_data = LuaGet<int>(lua_g, -1 + __index);__array.push_back(tmp);break;case LH_LuaType::LH_Lua_Number:tmp.lh_number_data = LuaGet<double>(lua_g, -1 + __index);__array.push_back(tmp);break;case LH_LuaType::LH_Lua_String:tmp.lh_string_data = LuaGet<char*>(lua_g, -1 + __index);__array.push_back(tmp);break;default:throw std::logic_error("LuaHelp::GetResult LH_LuaType Error!");break;}__index++;}lua_pop(lua_g, _argsize);return __array;}};
LuaScript.h,面向对象 模板封装。
/*************************************************vic.MINg 2021/10/11使用 模板 对 lua 的封装************************************************/#pragma once#include <iostream>#include <stdexcept>#include <vector>#include "LuaHelper.h"// 面向对象 封装class LuaScript{public:LuaScript():m_lua(NULL) {}~LuaScript() {if (m_lua) lua_close(m_lua);}bool CreateLuaState(){if (m_lua) return true;m_lua = luaL_newstate();if (m_lua == NULL)return false;luaL_openlibs(m_lua);return true;}void PrintStack_Info(const char* tag = NULL){LuaHelp::PrintStack_Info(m_lua, tag);}void PrintStack_Size(const char* tag = NULL){LuaHelp::PrintStack_Size(m_lua, tag);}bool DoFile(const char* file_name) {if (file_name == NULL) return false;if (luaL_dofile(m_lua, file_name) != 0){char* error_string = (char*)lua_tostring(m_lua, -1);throw std::logic_error(error_string);lua_pop(m_lua, 1);return false;}return true;}bool DoString(char* lua_string) {if (lua_string == NULL){return false;}if (luaL_dostring(m_lua, lua_string) != 0){char* error_string = (char*)lua_tostring(m_lua, -1);throw std::logic_error(error_string);lua_pop(m_lua, 1);return false;}return true;}inline bool GetGlobal(const char* name){return LuaHelp::GetGlobal(m_lua, name);}inline bool SetGlobal(const char* name){return LuaHelp::SetGlobal(m_lua, name);}inline lua_State* GetLuaState(){return m_lua;}template<typename _Ty>inline bool LuaCheck(int index = -1){return LuaHelp::LuaCheck<_Ty>(index);}template<typename _Ty>inline _Ty LuaGet(int index = -1, bool _pop = false){return LuaHelp::LuaGet<_Ty>(GetLuaState(), index, _pop);}template<typename _Type>inline void LuaPush(_Type data){LuaHelp::LuaPush<_Type>(GetLuaState(), data);}template<typename _Ty>inline _Ty LuaGetGlobal(char*global, bool _pop = true){return LuaHelp::LuaGetGlobal<_Ty>(GetLuaState(), global, _pop);}template<typename _Ty>inline bool LuaSetGlobal(_Ty data, char*global){return LuaHelp::LuaSetGlobal<_Ty>(m_lua, data, global);}template<typename _Ret, typename... _Args>inline _Ret CallLuaFuction_return_oneValue(const char* FunctionName, _Args...args){return LuaHelp::CallLuaFuction_return_oneValue<_Ret>(GetLuaState(), FunctionName, args...);}template< typename... _Args>inline void CallLuaFuction_return_void(const char* FunctionName, _Args...args){LuaHelp::CallLuaFuction_return_void(GetLuaState(), FunctionName, args...);}template< typename... _Args>inline LuaScript& CallLuaFuction_return_multValues(const char* FunctionName, _Args...args){LuaHelp::CallLuaFuction_return_multValues(GetLuaState(), FunctionName, args...);return *this;}template< typename... _Args>std::vector<LuaHelp::LH_LuaData> GetResult(_Args...args){auto tmp = std::move(LuaHelp::GetResult(m_lua, args...));return tmp;}private:lua_State * m_lua;};
函数封装, Lua 调用 C++ 函数
Lua 调用 C++ 函数时,C++注册函数的五种方法。
LuaRegFuncs.h
#pragma once#include "../include/LuaScript.h"#include "../include/LuaEx.hpp"class LuaRegFuncs : public LuaScript{public:void RegFuncs();};
LuaRegFuncs.cpp
#include "LuaRegFuncs.h"#include <functional>int show_luaproject_info1(lua_State *L){std::cout << __FUNCTION__ << std::endl;printf("Show LuaProject C++ Info 1.\n");return 0;}int show_luaproject_info2(lua_State *L){std::cout << __FUNCTION__ << std::endl;printf("Show LuaProject C++ Info 2.\n");return 0;}int show_luaproject_openlib(lua_State *L){std::cout << __FUNCTION__ << std::endl;struct luaL_Reg regfuc[]{{ "show_luaproject_info1", show_luaproject_info1 },{ "show_luaproject_info2", show_luaproject_info2 },{ NULL,NULL }};luaL_newlib(L, regfuc);return 1;}void LuaRegFuncs::RegFuncs(){struct luaL_Reg regfuc[]{{ "show_luaproject_info1", show_luaproject_info1 },{ "show_luaproject_info2", show_luaproject_info2 },{ NULL,NULL }};std::function<void()> lua_pushcfunction_RegFuncs = [&](){lua_pushcfunction(GetLuaState(), &show_luaproject_info1);SetGlobal("show_luaproject_info1");lua_pushcfunction(GetLuaState(), &show_luaproject_info2);SetGlobal("show_luaproject_info2");};std::function<void()> luaL_newlib_RegFuncs = [&](){luaL_newlib(GetLuaState(), regfuc);SetGlobal("luaL_newlib_RegFuncs");};std::function<void()> lua_newtable_luaL_setfuncs_RegFuncs = [&](){lua_newtable(GetLuaState());luaL_setfuncs(GetLuaState(), regfuc, 0);SetGlobal("lua_newtable_luaL_setfuncs_RegFuncs");};std::function<void()> lua_table_reg_RegFuncs = [&](){// 创建一个Table 压入键值对lua_newtable(GetLuaState());for (auto& v : regfuc){if (v.func == NULL || v.name == NULL){break;}LuaPush<const char*>(v.name);LuaPush<lua_CFunction>(v.func);lua_rawset(GetLuaState(), -3);}SetGlobal("lua_table_reg_RegFuncs");};std::function<void()> luaL_requiref_RegFuncs = [&](){luaL_requiref(GetLuaState(), "luaL_requiref_RegFuncs", show_luaproject_openlib, 1);lua_pop(GetLuaState(), 1);};if (CreateLuaState()){lua_pushcfunction_RegFuncs();luaL_newlib_RegFuncs();lua_newtable_luaL_setfuncs_RegFuncs();lua_table_reg_RegFuncs();luaL_requiref_RegFuncs();}}
类封装,Lua 调用 C++ 类
这里有个 Teacher 类,这里实现对该类的封装,看看如何 在 Lua 中调用 C++ 类。
Teacher.h
#pragma once#include <iostream>#include <string>class Teacher{public://构造/析构函数Teacher();~Teacher();//get/set函数std::string get_name();void set_name(std::string name);unsigned get_age();void set_age(unsigned age);//打印函数void print();private:std::string _name;unsigned _age;};
Teacher.cpp
#include "Teacher.h"Teacher::Teacher():_name("Empty"),_age(0){std::cout << "Teacher Constructor" << std::endl;}Teacher::~Teacher(){std::cout << "Teacher Destructor" << std::endl;}std::string Teacher::get_name(){return _name;}void Teacher::set_name(std::string name){_name = name;}unsigned Teacher::get_age(){return _age;}void Teacher::set_age(unsigned age){_age = age;}void Teacher::print(){std::cout << "name :" << _name << " age : " << _age << std::endl;}
编写对 Teacher 的封装代码:
TeacherRegFuncs.h
#pragma once#include "LuaEx.hpp"#include "Teacher.h"//------定义相关的全局函数------//创建对象int lua_create_new_teacher(lua_State* L);//get/set函数int lua_get_name(lua_State* L);int lua_set_name(lua_State* L);int lua_get_age(lua_State* L);int lua_set_age(lua_State* L);//打印函数int lua_print(lua_State* L);//转换为字符串函数int lua_teacher2string(lua_State* L);//自动GCint lua_auto_gc(lua_State* L);//------注册全局函数供Lua使用------//构造函数static const luaL_Reg lua_reg_teacher_constructor_funcs[] = {{ "create", lua_create_new_teacher },{ NULL, NULL }};//成员操作函数static const luaL_Reg lua_reg_teacher_member_funcs[] = {{ "get_name", lua_get_name },{ "set_name", lua_set_name },{ "get_age", lua_get_age },{ "set_age", lua_set_age },{ "print", lua_print },{ "__gc", lua_auto_gc }, //注册Lua内部函数__gc{ "__tostring", lua_teacher2string },{ NULL, NULL },c++};int luaopen_teacher_libs(lua_State* L);
TeacherRegFuncs.cpp
#include "TeacherRegFuncs.h"int lua_create_new_teacher(lua_State* L){//创建一个对象指针放到stack里,返回给Lua中使用,userdata的位置-1Teacher** t = (Teacher**)lua_newuserdata(L, sizeof(Teacher*));*t = new Teacher();//Lua->stack,得到全局元表位置-1,userdata位置-2luaL_getmetatable(L, "TeacherClass");//将元表赋值给位置-2的userdata,并弹出-1的元表lua_setmetatable(L, -2);return 1;}int lua_get_name(lua_State* L){//得到第一个传入的对象参数(在stack最底部)Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");luaL_argcheck(L, t != NULL, 1, "invalid user data");//清空stacklua_settop(L, 0);//将数据放入stack中,供Lua使用lua_pushstring(L, (*t)->get_name().c_str());return 1;}int lua_set_name(lua_State* L){//得到第一个传入的对象参数Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");luaL_argcheck(L, t != NULL, 1, "invalid user data");luaL_checktype(L, -1, LUA_TSTRING);std::string name = lua_tostring(L, -1);(*t)->set_name(name);return 0;}int lua_get_age(lua_State* L){Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");luaL_argcheck(L, t != NULL, 1, "invalid user data");lua_pushinteger(L, (*t)->get_age());return 1;}int lua_set_age(lua_State* L){Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");luaL_argcheck(L, t != NULL, 1, "invalid user data");luaL_checktype(L, -1, LUA_TNUMBER);(*t)->set_age((unsigned)lua_tointeger(L, -1));return 0;}int lua_print(lua_State* L){Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");luaL_argcheck(L, t != NULL, 1, "invalid user data");(*t)->print();return 0;}int lua_teacher2string(lua_State* L){Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");luaL_argcheck(L, t != NULL, 1, "invalid user data");lua_pushfstring(L, "This is teacher name : %s age : %d !", (*t)->get_name().c_str(), (*t)->get_age());return 1;}int lua_auto_gc(lua_State* L){Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");luaL_argcheck(L, t != NULL, 1, "invalid user data");if (t) {delete *t;}return 0;}int luaopen_teacher_libs(lua_State* L){//创建全局元表(里面包含了对LUA_REGISTRYINDEX的操作),元表的位置为-1luaL_newmetatable(L, "TeacherClass");//将元表作为一个副本压栈到位置-1,原元表位置-2lua_pushvalue(L, -1);//设置-2位置元表的__index索引的值为位置-1的元表,并弹出位置-1的元表,原元表的位置为-1lua_setfield(L, -2, "__index");//将成员函数注册到元表中(到这里,全局元表的设置就全部完成了)luaL_setfuncs(L, lua_reg_teacher_member_funcs, 0);//注册构造函数到新表中,并返回给LualuaL_newlib(L, lua_reg_teacher_constructor_funcs);return 1;}
为了方便,我们把注册的代码添加到之前的 LuaRegFuncs 类中,相关代码如下:
#include "Teacher.h"#include "TeacherRegFuncs.h"...static const luaL_Reg regclass[] = {{ "base", luaopen_base }, // 系统模块{ "Teacher", luaopen_teacher_libs }, // 模块名字 Teacher,注册函数 luaopen_teacher_libs{ NULL, NULL }};...const luaL_Reg* lua_reg = regclass;for (; lua_reg->func; ++lua_reg) {luaL_requiref(GetLuaState(), lua_reg->name, lua_reg->func, 1);lua_pop(GetLuaState(), 1);}...
C++ 和 Lua 相互调用测试
我们完成了相关代码的封装,现在我们来做一些必要的测试:
先写一份 Lua 脚本,需求如下:
•编写无返回值、一个返回值、多个返回值函数。•编写函数,调用 C++ 中的函数和类。•最终,我们会在 C++ 中调用 这些 Lua 函数。
luascript_test.lua
function show_luascript_test1(a,b)print("Test1",a,b)return a+bendfunction show_luascript_test2(A,B,C)print("Test3 Lua",A,B,C)return 111,"LUA",333.6endfunction teacher_print()local teacher_obj = Teacher.create()teacher_obj:set_name("Jack")teacher_obj:print()--使用内部的__tostring函数进行打印print(teacher_obj)--下面的代码也是可行的--teacher_obj.set_name(teacher_obj,"Jack")--teacher_obj.print(teacher_obj)--让其进行自动gcteacher_obj = nil--手动强制gc--collectgarbage("collect")endfunction reg_funcs()print("-----------------lua_pushcfunction_RegFuncs-----------------")show_luaproject_info1()show_luaproject_info2()print("-----------------luaL_newlib_RegFuncs-----------------")luaL_newlib_RegFuncs.show_luaproject_info1()luaL_newlib_RegFuncs.show_luaproject_info2()print("-----------------lua_newtable_luaL_setfuncs_RegFuncs-----------------")lua_newtable_luaL_setfuncs_RegFuncs.show_luaproject_info1()lua_newtable_luaL_setfuncs_RegFuncs.show_luaproject_info2()print("-----------------lua_table_reg_RegFuncs-----------------")lua_table_reg_RegFuncs.show_luaproject_info1()lua_table_reg_RegFuncs.show_luaproject_info2()print("-----------------luaL_requiref_RegFuncs-----------------")--local luaL_requiref_RegFuncs = require "luaL_requiref_RegFuncs"luaL_requiref_RegFuncs.show_luaproject_info1()luaL_requiref_RegFuncs.show_luaproject_info2()end
编写代码,加载 这个 Lua 文件,并且实现调用上面的 Lua 函数。
main.cpp
#include <stdio.h>#include <string>#include <assert.h>#include <iostream>#include "DirectoryManager.h"#include "LuaRegFuncs.h"int main(int argc, char** argv){LuaRegFuncs* lua_reg_funcs = new LuaRegFuncs();lua_reg_funcs->RegFuncs();std::string strLuaScript;#ifdef _WIN32strLuaScript = DirectoryManager::GetExeDirectory() + "scripts/luascript_test.lua";#elsestrLuaScript = "scripts/luascript_test.lua";#endif// 加载一个lua脚本if (!lua_reg_funcs->DoFile(strLuaScript.c_str())){delete lua_reg_funcs;return -1;}// 一返回值函数的调用auto sum_ab = lua_reg_funcs->CallLuaFuction_return_oneValue<int>("show_luascript_test1", 1, 10);std::cout << "show_luascript_test1 Result:" << sum_ab << std::endl;// 无返回值函数的调用// Lua 函数中,调用 C++ 函数的应用lua_reg_funcs->CallLuaFuction_return_void("reg_funcs");// 多返回值函数的调用lua_reg_funcs->CallLuaFuction_return_multValues<int, const char*, float>("show_luascript_test2", 2, "vic.MINg", 3.14f);auto arrResult = lua_reg_funcs->GetResult(LuaHelp::LH_LuaType::LH_Lua_Int, LuaHelp::LH_LuaType::LH_Lua_String, LuaHelp::LH_LuaType::LH_Lua_Number);std::cout << "show_luascript_test2 Result:" << arrResult[0].lh_int_data << std::endl;std::cout << "show_luascript_test2 Result:" << arrResult[1].lh_string_data << std::endl;std::cout << "show_luascript_test2 Result:" << arrResult[2].lh_number_data << std::endl;// Lua 函数中,调用 C++ 类的应用lua_reg_funcs->CallLuaFuction_return_void("teacher_print");system("pause");delete lua_reg_funcs;return 0;}
运行程序,看一下成果物:





