根据文档,可知可以在lua中派生c++类,进而在lua中实现多态性
https://www.rasterbar.com/products/luabind/docs.html#deriving-in-lua
然而lua类实例化的对象,实际分为两部分数据
https://www.rasterbar.com/products/luabind/docs.html#slicing
+--------------------+
| C++ object | <- ownership of this part is transferred
| | to c++ when adopted
+--------------------+
| lua class instance | <- this part is garbage collected when
| and lua members | instance is adopted, since it cannot
+--------------------+ be held by c++.
通常需要把lua派生的对象传回c++,让其调用虚接口virtual function
基类在C++中实现,并且导出到luabind
struct Base {
virtual void foo();
}
struct Base_Wrapper : Base, luabind::wrap_base {
virtual void foo() {
call<void>("foo");
}
static void default_foo(Base * ptr) {
return ptr->Base::foo();
}
}
struct Manager {
shared_ptr<Base> m_obj
void dofoo() {
if (m_obj)
m_obj->foo(); // 这里希望调用A在lua中的派生类对象实现的foo
}
}
Manager g_mgr;
module(L) [
class_<Base, Base_Wrapper, shared_ptr<Base> >("Base")
.def(constructor<>())
.def("foo", &Base::foo, &Base_Wrapper::default_foo)
, class_<Manager>("Manager")
.def_readwrite("obj", &Manager::m_obj)
];
luabind::globals(L)["mgr"]=&g_mgr;
留意此处Manager的m_obj是shared_ptr,期望是维护obj生存期
lua中派生C++对象,实现如下
class 'Derived'(Base)
function Derived:__init()
Base.__init(self)
end
function Derived:foo()
print("hello")
end
mgr.obj=Derived() -- 这里实例化Derived对象,并保存到 mgr.obj
那么一段时间之后在C++中调用 g_mgr.dofoo(),会引发断言异常 !lua_isnil(L, -1),位置luabind\wrapper_base.hpp(124)
template<class R BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
typename boost::mpl::if_<boost::is_void<R>
, luabind::detail::proxy_member_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
, luabind::detail::proxy_member_caller<R, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
call(char const* name BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _), detail::type_<R>* = 0) const
{
...
assert(!lua_isnil(L, -1));
这是因为lua的垃圾回收机制,将Derived 对象的lua部分销毁了,只保留了c++部分,导致 call<void>(“foo”) 找不到实现体
解决方案就是使用adopt policy,但是adopt不支持smart ptr,所以需要重新定义导出接口
#include <luabind/adopt_policy.hpp>
struct Base {
...
}
struct Base_Wrapper : Base, luabind::wrap_base {
...
}
struct Manager {
...
void setobj(Base * obj) { // 这里直接使用指针
m_obj.reset(obj);
}
}
Manager g_mgr;
module(L) [
class_<Base, Base_Wrapper/*, shared_ptr<Base>*/ >("Base") // 使用raw ptr
...
, class_<Manager>("Manager")
.def("setobj", &Manager::setobj, adopt(_2)) // 使用adopt policy
];
luabind::globals(L)["mgr"]=&g_mgr;
在lua中直接传入创建的对象,生存期会被转移到mgr
class 'Derived'(Base)
...
mgr:setobj(Derived())
相关代码:
luabind/back_reference.hpp
luabind/detail/instance_holder.hpp