我认为要让它工作,你必须像这样绑定你的派生类:
luabind::class_<Button, BaseWidget, std::shared_ptr<Button>> ("Button")
例如:
class BaseWidget
{
public:
static void Bind2Lua(lua_State* l)
{
luabind::module(l)
[
luabind::class_<BaseWidget, std::shared_ptr<BaseWidget>> ("BaseWidget")
.def(luabind::constructor<>())
];
}
virtual ~BaseWidget()
{
}
};
class Button : public BaseWidget
{
public:
static void Bind2Lua(lua_State* l)
{
luabind::module(l)
[
luabind::class_<Button, BaseWidget, std::shared_ptr<Button>> ("Button")
.def(luabind::constructor<>())
.def("Click", &Button::Click)
];
}
void Click()
{
std::cout << "Button::Click" << std::endl;
}
};
现在您可以将它与 shared_ptr 一起使用:
class Action
{
public:
void DoClick(const std::shared_ptr<Button>& b)
{
// perform click action
b->Click();
}
static void Bind2Lua(lua_State* l)
{
luabind::module(l)
[
luabind::class_<Action> ("Action")
.def(luabind::constructor<>())
.def("DoClick", &Action::DoClick)
];
}
};
在 lua 中:
b = Button()
a = Action()
a:DoClick(b)
原因是 luabind 使用带整数的类型 ID 系统(更准确地说,std::size_t 在inheritance.hpp 中定义)。
您可以使用以下函数获取任何已注册类型的类型 ID:
luabind::detail::static_class_id<T>(nullptr);
其中 T 是注册类。
在我的演示程序中,它们是:
- 基本小部件 = 3
- std::shared_ptr<BaseWidget> = 6
- 按钮 = 4
- std::shared_ptr< 按钮 > = 7
- 行动 = 5
所以当你从lua调用DoClick时,它会调用instance_holder.hpp中模板类pointer_holder的get成员:
std::pair<void*, int> get(class_id target) const
{
if (target == registered_class<P>::id)
return std::pair<void*, int>(&this->p, 0);
void* naked_ptr = const_cast<void*>(static_cast<void const*>(
weak ? weak : get_pointer(p)));
if (!naked_ptr)
return std::pair<void*, int>((void*)0, 0);
return get_class()->casts().cast(
naked_ptr
, static_class_id(false ? get_pointer(p) : 0)
, target
, dynamic_id
, dynamic_ptr
);
}
如您所见,如果目标类与注册的不同,它将尝试进行强制转换。
这就是事情变得有趣的地方。如果您将 Button 类声明为
luabind::class_<Button, BaseWidget,std::shared_ptr<BaseWidget>>("Button")
然后该实例将作为一个 shared_ptr 保存到 BaseWidget,因此 cast 函数将尝试从 BaseWidget (3) 转换为 std::shared_ptr< Button > (7) 并且失败。如果 luabind 支持 base-to-derived 转换,它可以工作,但它似乎不支持。
但是,如果您将 Button 类声明为
luabind::class_<Button, BaseWidget, std::shared_ptr<Button>> ("Button")
然后该实例将作为一个 shared_ptr 保存到 Button ,然后目标 id 将匹配注册的类型。get 函数将在第一次返回时分支,从不打扰演员表。
您还可以在 pastebin 找到我在这里使用的自包含程序。
这里有一个有趣的断点列表,你可以设置看看发生了什么(luabind 版本 900):
- instance_holder.hpp 中的第 94 行(pointer_holder::get 的第一行)
- instance.cpp 中的第 143 行(cast_graph::impl::cast 的第一行)