在上一篇《Luapp C++ 导出函数/类与Lua交互》介绍了如何导出类和函数。
这篇简单说说导出类虚函数的使用与对象传递
先看看基类和派生类的定义
//基类,含有一个虚函数
class TestClassBase {
public:
virtual void print() const {
printf("base class print\n");
}
};
//派生类:导出
class TestClass:public TestClassBase {
public:
TestClass() {//从Lua创建 也可以在包含luaExportClass.h前重新定义宏 LUA_EXPORT_NEWOBJ,来自定义创建类对象,默认直接 new
m_createByLua = true;
printf("TestClass Constructor:Lua\n");
}
TestClass(int ) {//从c++创建
m_createByLua = false;
printf("TestClass Constructo:C++\n");
}
~TestClass() {
if(m_createByLua)
printf("TestClass Destructor:Lua\n");
else
printf("TestClass Destructor:C++\n");
}
virtual void print() const override{
if(m_createByLua)
printf("subclass:I am create by lua\n");
else
printf("subclass:I am create by c++\n");
}
//该函数未导出
void printcpp() {
printf("not export function,only use in c++\n");
}
int add(int a, int b) {
return a + b;
}
void setv(int value) {
m_value = value;
}
int getv() {
return m_value;
}
int m_value;
bool m_createByLua;
//导出申明
LUA_CLASS_EXPORT_DECLARE;
};
导出实现宏,类似MFC消息映射
//不需要导出的成员函数,不写在这里即可
LUA_CLASS_EXPORT_BEGIN(TestClass) //导出实现开始
LUA_CLASS_EXPORT_FUNC("add", &TestClass::add) //设定导出的成员函数名和函数地址
LUA_CLASS_EXPORT_FUNC("getvalue", &TestClass::getv) //在lua里换个名字
LUA_CLASS_EXPORT_FUNC("setv", &TestClass::setv)
LUA_CLASS_EXPORT_FUNC("ppt", &TestClassBase::print) //基类虚函数,调用派生类的函数
LUA_CLASS_EXPORT_END() //结束
这样就完成了派生类 TestClass 的导出。
从lua获取所需的参数,返回值给lua,都是自动操作。
使用时不用关心lua栈。
1.Lua创建c++对象,并在lua使用
lua::LuaWrap lw;
lw.Init();//对象初始化
//调用导出类的 LuaClassRegister 函数导出该类到当前状态机
TestClass::LuaClassRegister(lw.get());
//对象在lua生成,并调用成员函数
lw.RunString<void>(
R"(
local t1 = TestClass() --new object:local
local v = t1:add(1, 4) -- 5
t1:setv(6)
t2 = TestClass() --new object:global
t2:setv(v)
print('t1:getvalue()='..t1:getvalue()) --6
print('t2:getvalue()='..t2:getvalue()) --5
t1:ppt() --print
)"
);
运行结果:
2.将Lua创建的对象,传递到c++使用
上面演示了在lua里创建TestClass对象并调用成员函数和虚函数。
现在,我们将lua创建的c++对象传递出来给c++调用
//定义一个 lambda ,导出给lua,接收lua传递的参数
auto UseLuaObj = [](void *o) {
//如果参数为lightuserdata(先由c++通过void*传过去,再被传出来),则直接转换为对象指针
//所以void *根据具体情况使用
//这里接收lua传递过来的 TestClass 对象
auto pobj = *(TestClass **)o;
pobj->printcpp(); //打印,该函数未导出,仅能在c++里调用
};
lw.RegFunction("UseLuaObj", UseLuaObj);//注册函数 UseLuaObj 给 lua
lw.RunString<void>("UseLuaObj(t2)");//在lua里调用导出函数,将全局对象t2传出来
运行结果这里仅一条print,待会儿一起给出。
3.将在c++里创建的对象,传递给Lua使用
很多时候,我们已经在c++代码里创建了对象,想直接传递给lua使用,应该怎么操作呢?
可以这样实现:
首先在lua里定义一个函数,用一个参数接收c++传递的对象,c++传递时,使用 mtable类型即可
如下:
//对象已经在c++中生成,传递给lua使用
//编写一个lua函数,将c++创建的对象,传递给lua使用(该类已被导出)
TestClass tc(1);
lw.RunString<void>(
R"(
function PassByParam(p)
p:ppt() --print
end
)",//定义lua函数 PassByParam
"PassByParam",//调用lua函数 PassByParam
lua::mtable{&tc,"TestClass"});//将tc指针作为导出的TestClass传递给函数 PassByParam
也可以使用宏 LUA_EXPORT_METATABLE(TestClass) 获取到导出类的mtable名。
由c++创建,通过mtable方式传递给Lua使用的对象,由c++销毁,lua不参与其生命周期管理。
由Lua代码调用TestClass()创建的c++对象,由Lua创建也由Lua销毁(随userdata回收)。
最后整体运行结果如图:
小结:新提交的代码补充了mtable类型的使用,完善了c++创建的对象传递给lua使用的情况。
当前:
Lua创建c++对象,在Lua使用或传递给C++使用
C++创建对象,传递给Lua使用
都已经实现了,新的代码和测试代码已提交到github:GitHub - njzz/luapp: lua and cpp