C++与Lua交互 使用模板特化封装
发布于 2021-10-18 07:23
序
当前 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.pi
end
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.读取table
lua_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.关闭state
lua_close(L);
return;
}
使用 C++ 模板封装 Lua
配置 Lua 环境、植入新版本的 Lua 库函数
将 Lua 的头文件和编译的库文件,添加到工程文件中。
我们需要植入一些先版本的 Lua 库函数。因为它们比较好用~ 可以更方便的让 C++ 和 Lua 的相互交互。
创建一个 LuaEx.hpp 文件,包含头文件,并植入函数:
/***************************************************************************************************************************************************
vic.MINg 2021/10/11
lua 函数扩展,由于使用 lua 版本 5.1.5,一些比较有用的函数 没有,这里将这些函数 扩展到这里,也可以了解 lua 的实现
**************************************************************************************************************************************************/
extern "C"
{
}
inline 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));
// else
lua_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 */
}
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
(luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
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;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 特化 LuaCheck
template<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;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 特化 LuaGet
template<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;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 特化 LuaPush
template<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);
//自动GC
int 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的位置-1
Teacher** t = (Teacher**)lua_newuserdata(L, sizeof(Teacher*));
*t = new Teacher();
//Lua->stack,得到全局元表位置-1,userdata位置-2
luaL_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");
//清空stack
lua_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的操作),元表的位置为-1
luaL_newmetatable(L, "TeacherClass");
//将元表作为一个副本压栈到位置-1,原元表位置-2
lua_pushvalue(L, -1);
//设置-2位置元表的__index索引的值为位置-1的元表,并弹出位置-1的元表,原元表的位置为-1
lua_setfield(L, -2, "__index");
//将成员函数注册到元表中(到这里,全局元表的设置就全部完成了)
luaL_setfuncs(L, lua_reg_teacher_member_funcs, 0);
//注册构造函数到新表中,并返回给Lua
luaL_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+b
end
function show_luascript_test2(A,B,C)
print("Test3 Lua",A,B,C)
return 111,"LUA",333.6
end
function 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)
--让其进行自动gc
teacher_obj = nil
--手动强制gc
--collectgarbage("collect")
end
function 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 _WIN32
strLuaScript = DirectoryManager::GetExeDirectory() + "scripts/luascript_test.lua";
#else
strLuaScript = "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;
}
运行程序,看一下成果物:
本文来自网络或网友投稿,如有侵犯您的权益,请发邮件至:aisoutu@outlook.com 我们将第一时间删除。
相关素材