それが機能するには、次のように派生クラスをバインドする必要があると思います。
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)
];
}
};
ルアで:
b = Button()
a = Action()
a:DoClick(b)
その理由は、luabind が整数の type-id システムを使用するためです (より正確には、inheritance.hpp で定義されている std::size_t)。
次の関数を使用して、登録されている任意のタイプのタイプ 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")
インスタンスは BaseWidget への shared_ptr として保持されるため、キャスト関数は BaseWidget (3) から std::shared_ptr< Button > (7) にキャストしようとしますが、失敗します。luabind がベースから派生への変換をサポートしていれば機能する可能性がありますが、そうではないようです。
ただし、Button クラスを次のように宣言した場合
luabind::class_<Button, BaseWidget, std::shared_ptr<Button>> ("Button")
インスタンスはボタンへのshared_ptrとして保持され、ターゲットIDは登録されたタイプと一致します。get 関数は最初のリターンで分岐し、キャストに煩わされることはありません。
ここで使用した自己完結型のプログラムは、pastebin にもあります。
そして、何が起こっているかを見るために設定できる興味深いブレークポイントのリストです (luabind バージョン 900):
- instance_holder.hpp の 94 行目 (pointer_holder::get の最初の行)
- instance.cpp の 143 行目 (cast_graph::impl::cast の最初の行)